日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

线段树专辑——pku 2886 Who Gets the Most Candies?

發布時間:2023/11/27 生活经验 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线段树专辑——pku 2886 Who Gets the Most Candies? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://poj.org/problem?id=2886

恩,分糖果,快樂的童年啊!

題目意思大概n個小孩圍成一個圈,每個小孩手里有張卡片,記錄著一個數字。開始從第k個孩子,該孩子離開圈子,然后告訴別人他手里的數字,接下來便從位于該孩子的位置加上孩子手中的數字的孩子開始,直到所有的孩子都離開了圈子,游戲便結束。每個跳出圈子的孩子都能得到一定的糖果,數目是他跳出圈子的順序數的因子數之和。 例如第6個跳出的孩子能得到(1,2,3,6)四個糖果。

?

這個游戲,其實和猴子選大王是一樣的!只要注意好求解相對位置即可,所謂相對位置,例如:

a,b,c,d四個人,a對應1,b對應2,c對應3,d對應4.但是當b不在以后,c便相對的為2,d也相對的為3.

然后利用線段樹,輕松解決!

?

這里關鍵是學習了一下反素數表。

反素數:

對于任何正整數x,其約數的個數記做g(x)。例如g(1)=1,g(6)=4。
如果某個正整數x滿足:對于任意i(0 < i < x),都有g(i) < g(x),則稱x為反素數。

而反素數表就是對應上面反素數所建立的一張表,這張表好處多多,例如給你一個n,你便可以輕松的找出1~~n范圍內,誰的因子數之和最多!

給出個簡單的打表方法

View Code
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

int dp[600001];

int main()
{
int i,j;
freopen("D:\\in.txt","w",stdout);
memset(dp,0,sizeof(dp));
for(i=1;i<=500000;i++)
{
for(j=1;j<=500000;j++)
{
if(i*j<=600000)
dp[i*j]++;
}
}
int max=0;
for(i=2;i<=600000;i++)
{
if(dp[i]>max)
{
max=dp[i];
cout<<i<<",";
}
}
cout<<endl<<endl;
max=0;
for(i=2;i<=600000;i++)
{
if(dp[i]>max)
{
max=dp[i];
cout<<dp[i]<<",";
}
}
return 0;
}

?

這是一個效率很低的程序,只是為了這道題打表而已。

?

接下來模擬猴子選大王就是了,當給定一個n的時候,先找出1~~n內因子數之和最大的那個數,因子數之和便是candy的答案,假設那個數是m,那么模擬到第m個人的時候,那個人便也是答案!

?

View Code
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

int max_turn[40]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960,554400};
int max_candy[40]={1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,64,72,80,84,90,96,100,108,120,128,144,160,168,180,192,200,216};

struct child
{
char name[10];
int pos;
};

child num[500001];
int n,k,pos;

struct node
{
int l;
int r;
int left;
};

node tree[2500000];

void build(int i,int l,int r)
{
tree[i].l=l;
tree[i].r=r;
tree[i].left=r-l+1;
if(l==r)
return;
int mid=(l+r)/2;
build(2*i,l,mid);
build(2*i+1,mid+1,r);
}

void updata(int i,int w)
{
if(tree[i].l==tree[i].r)
{
tree[i].left--;
pos=tree[i].l; //記錄目前的實際位置
return;
}
if(tree[2*i].left>=w)
updata(2*i,w);
else if(tree[2*i+1].left>=w-tree[2*i].left)
updata(2*i+1,w-tree[2*i].left);
tree[i].left=tree[2*i].left+tree[2*i+1].left;
}

int main()
{
int i,turn,&mod=tree[1].left,candy;
freopen("D:\\in.txt","r",stdin);
while(scanf("%d%d",&n,&k)==2)
{
build(1,1,n);
for(i=1;i<=n;i++)
{
scanf("%s %d",num[i].name,&num[i].pos);
}
i=0;
while(max_turn[i]<=n) //尋找最大的n'
i++;
i--;
candy=max_candy[i]; //記錄最多的糖果
turn=max_turn[i]; //第max_turn[i]出來的人將得到最多的糖果
pos=0;
num[0].pos=0;
for(i=0;i<turn;i++)
{
if(num[pos].pos>0) //求解相對剩余位置
{
k=((k+num[pos].pos-1)%mod+mod)%mod;
if(k==0)
k=mod;
}
else
{
k=((k+num[pos].pos)%mod+mod)%mod;
if(k==0)
k=mod;
}
updata(1,k);
}
printf("%s %d\n",num[pos].name,candy);
}
return 0;
}



轉載于:https://www.cnblogs.com/ka200812/archive/2011/11/14/2248914.html

總結

以上是生活随笔為你收集整理的线段树专辑——pku 2886 Who Gets the Most Candies?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。