POJ - 2886 Who Gets the Most Candies
筛法+划分树。
枚举因子,类似筛法计算因子数量,复杂度为n/2 + n/3 + ... + n/n ≈ O(nlogn)。
值域已知,只有删除操作,寻找kth,用划分树就好了O(nlogn)。二分+树状数组也可以,只是复杂度多乘一个logn。
/********************************************************* * ------------------ * * author AbyssalFish * **********************************************************/ #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<queue> #include<vector> #include<stack> #include<vector> #include<map> #include<set> #include<algorithm> #include<cmath> #include<numeric> using namespace std; const int MAX_SIZE = 1<<20, MAX_N = 5e5, LEN = 11; int s[MAX_SIZE]; int N, K; #define para int o = 1, int l = 0,int r = N-1 #define Tvar int mid = (l+r)>>1, lc = (o<<1), rc = (o<<1|1); #define lsn lc, l, mid #define rsn rc, mid+1, r void build(para) { s[o] = r-l+1; if(l == r) return; else { Tvar build(lsn); build(rsn); } } int q_modify(int k, para) { s[o]--; if(l == r){ return l; } else { Tvar if(k<=s[lc]) return q_modify(k, lsn); return q_modify(k-s[lc], rsn); } } char name[MAX_N][LEN]; int card[MAX_N]; int Fp[MAX_N+1]; #define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif //cout<<(1<<20);//ceil(log2(5e5)+1); scanf("%d%d",&N,&K); for(int i = 2; i <= N; i++){ for(int j = i; j <= N; j += i){ Fp[j]++; } } int tar = 1; for(int i = 2; i <= N; i++){ if(Fp[tar] < Fp[i]) tar = i; } for(int i = 0; i < N; i++) scanf("%s%d", name[i], card+i); build(); int pos , kth = K-1, mn = N-tar; for(int n = N; n-- > mn; ){ pos = q_modify(kth+1);//位置下标从必须开始0,这样才方便取模 if(n){ if(card[pos] > 0) card[pos]--; //可以看作往后移动一下,然后把kth去掉 kth = (card[pos]+kth)%n; if(kth < 0) kth += n; } } printf("%s %d\n", name[pos], Fp[tar]+1); return 0; }
12.8更新~
其实树状数组也可以logN的找到kth的, 就像猜数字一样不断缩小范围。
/********************************************************* * ------------------ * * author AbyssalFish * **********************************************************/ #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<queue> #include<vector> #include<stack> #include<vector> #include<map> #include<set> #include<algorithm> #include<cmath> #include<numeric> using namespace std; const int MAX_N = 5e5+1, LEN = 11; char name[MAX_N][LEN]; int card[MAX_N]; int N, K; int C[MAX_N]; int q_Kth(int k) { int p = 0, c = 0; for(int i = 19; i >= 0; i--){ p += 1<<i; (p >= N || c + C[p] >= k)? p -= 1<<i : c += C[p]; } return p+1; } void sub(int x) { while(x <= N){ C[x]--; x += x&-x; } } int Fp[MAX_N+1]; //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif //cout<<(1<<20);//ceil(log2(5e5)+1); scanf("%d%d",&N,&K); for(int i = 2; i <= N; i++){ for(int j = i; j <= N; j += i){ Fp[j]++; } } int tar = 1; for(int i = 2; i <= N; i++){ if(Fp[tar] < Fp[i]) tar = i; } for(int i = 0; i < N; i++) scanf("%s%d", name[i], card+i); for(int i = 1; i <= N; i++) { C[i] = i&-i; } int pos , k = K-1, mn = N-tar; for(int n = N; n-- > mn; ){ pos = q_Kth(k+1)-1; sub(pos+1); if(n){ if(card[pos] > 0) card[pos]--; k = (card[pos]+k)%n; if(k < 0) k += n; } } printf("%s %d\n", name[pos], Fp[tar]+1); return 0; }