挑战练习题3.3 POJ 2886 Who Gets the Most Candies? 树状数组
题目链接:
http://poj.org/problem?id=2886
题意:
抢糖:N个熊孩子围成一个圈,从第K个开始淘汰,每淘汰一个,出示手中的数字,决定下一个淘汰者,正数表示左手第n个,负数反之。每个人可以拿到的存活回数的因数个数的糖果,求拿到最多糖果数的孩子的名字以及糖果数。
题解:
http://www.hankcs.com/program/algorithm/poj-2886-who-gets-the-most-candies.html
代码:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 typedef long long ll; 6 #define MS(a) memset(a,0,sizeof(a)) 7 #define MP make_pair 8 #define PB push_back 9 const int INF = 0x3f3f3f3f; 10 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 11 inline ll read(){ 12 ll x=0,f=1;char ch=getchar(); 13 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 ////////////////////////////////////////////////////////////////////////// 18 const int maxn = 5e5+10; 19 20 int factor_table[maxn]; 21 char name[maxn][16]; 22 int integer[maxn]; 23 24 void init_factor_table(int n){ 25 fill(factor_table,factor_table+n+1,1); 26 for(int i=2; i<=n; i++){ 27 if(factor_table[i]==1){ 28 for(int j=i; j<=n; j+=i){ 29 int k = 0; 30 for(int m=j; m%i==0; m/=i,++k); 31 factor_table[j] *= (k+1); 32 } 33 } 34 } 35 } 36 37 struct BinaryIndexTree{ 38 int bit[maxn]; 39 int size; 40 void init(int size){ 41 this->size = size; 42 MS(bit); 43 } 44 45 int sum(int i){ 46 int s = 0; 47 while(i > 0){ 48 s += bit[i]; 49 i -= i&-i; 50 } 51 return s; 52 } 53 void add(int i,int v){ 54 ++i; 55 while(i < maxn){ 56 bit[i] += v; 57 i += i&-i; 58 } 59 } 60 61 int binary_search(int id){ 62 int l=0,r=size,res=0; 63 while(l<=r){ 64 int mid = (l+r)/2; 65 if(sum(mid) <= id) res=mid,l=mid+1; // mid是最初的编号 66 else r=mid-1; 67 } 68 return res; 69 } 70 }T; 71 72 int main(){ 73 int N,K; 74 init_factor_table(maxn); 75 while(cin>>N>>K){ 76 --K; 77 T.init(N); 78 for(int i=0; i<N; i++){ 79 scanf("%s %d",name[i],&integer[i]); 80 T.add(i,1); 81 } 82 int candies=-1,index; 83 for(int i=0; i<N; i++){ 84 if(candies < factor_table[i+1]){ 85 candies = factor_table[i+1]; 86 index = K; 87 } 88 89 T.add(K,-1); 90 if(i < N-1){ 91 int mod = N-i-1; 92 int id = T.sum(K)+integer[K]+(integer[K]>0 ? -1 : 0); // T.sum(K)表示第K个编号的人是当前轮的第几个。id是下一个剔除的人排在当前序列中的第几个 93 id = (id%mod+mod)%mod; // id可能是负的很大的数 94 K = T.binary_search(id); // 找到下一个剔除的最初编号 95 } 96 } 97 98 cout << name[index] << " " << candies << endl; 99 } 100 101 return 0; 102 }