Submission #132066

#TimeUsernameProblemLanguageResultExecution timeMemory
132066dragonslayeritFish (IOI08_fish)C++14
100 / 100
1289 ms61336 KiB
#include <cstdio> #include <algorithm> #include <vector> //Strategy: //Sort fishes by size //Relabel gems by last appearance (e.g. gem of largest fish is 0) //count multisets of gems => count multisets of fish such that if a fish is chosen, all smaller fish with same gem are chosen //For the actual subset of fish, some gem will be chosen to be "boosted" to the largest fish with that gem. //Iterate over last fish in multiset (pre-boosting) and count number of valid subsets //A multiset is bad iff no gem in the prefix is present and the largest fish's gem cannot be boosted. int N,MOD; int cps[500005]; int cps_size=0; int freq[500005]; int freq2[500005]; int last[500005]; int half[500005]; int prev[500005]; struct Fish{ int size,gem; bool operator<(Fish f)const{ return size<f.size; } }fishes[500005]; struct Op{ int sgn; int l,r,x; Op(int sgn,int l,int r,int x):sgn(sgn),l(l),r(r),x(x){ } }; std::vector<Op> ops[500005]; int st[1000010]; void pull(int i){ st[i]=1LL*st[i<<1]*st[i<<1|1]%MOD; } void update(int i){ for(st[i+=N]++;i>1;i>>=1){ pull(i>>1); } } int query(int a,int b){ int res=1; for(a+=N,b+=N;a<b;a>>=1,b>>=1){ if(a&1) res=1LL*res*st[a++]%MOD; if(b&1) res=1LL*res*st[--b]%MOD; } return res; } int main(){ int K; scanf("%d %d",&N,&K); scanf("%d",&MOD); for(int i=0;i<N;i++){ scanf("%d %d",&fishes[i].size,&fishes[i].gem); fishes[i].gem--; } std::sort(fishes,fishes+N); //Relabel gems by last appearance std::fill(cps,cps+K,-1); for(int i=N-1;i>=0;i--){ if(cps[fishes[i].gem]==-1){ cps[fishes[i].gem]=cps_size++; } } for(int i=0;i<N;i++){ fishes[i].gem=cps[fishes[i].gem]; } for(int k=0;k<K;k++){ last[k]=-1; } for(int i=0;i<N;i++){ prev[i]=last[fishes[i].gem]; last[fishes[i].gem]=i; } for(int k=0;k<K;k++){ int low=-1,high=N; while(high-low>1){ int mid=(low+high)/2; if(fishes[mid].size*2<=fishes[last[k]].size){ low=mid; }else{ high=mid; } } half[k]=high; //half[k] is index of first fish larger than fishes[last[k]].size/2 } int prefix=K-1;//largest gem # that can be "boosted" for(int i=0;i<N;i++){ //Counting configurations where fishes[i].gem occurs exactly freq[fishes[i].gem] times while(prefix>=0&&fishes[last[prefix]].size<2*fishes[i].size) prefix--; //Subtract multisets where none in prefix exist to be boosted ops[i+1].emplace_back(-1,prefix+1,K,fishes[i].gem); //Add back multisets where none in prefix exist to be boosted but fishes[i] can be boosted //Must be able to take all of fishes[i].gem before i if(prev[i]==-1||fishes[prev[i]].size*2<=fishes[last[fishes[i].gem]].size){ //Cannot have fish whose size <=1/2*size of last fish with fishes[i].gem ops[std::min(i,half[fishes[i].gem])].emplace_back(1,prefix+1,K,fishes[i].gem); } } //Count all ops[N].emplace_back(1,0,K,-1); //init st std::fill(st,st+N*2,1); //-1 for empty set int ans=-1; for(int i=0;i<=N;i++){ for(Op op:ops[i]){ int product=1; /* for(int k=op.l;k<op.r;k++){ if(k==op.x) continue; product=1LL*product*(freq[k]+1)%MOD; } */ if(op.x>=op.l&&op.x<op.r){ product=1LL*query(op.l,op.x)*query(op.x+1,op.r)%MOD; }else{ product=1LL*query(op.l,op.r); } ans=(ans+op.sgn*product)%MOD; } if(i==N) break; freq[fishes[i].gem]++; update(fishes[i].gem); } printf("%d\n",(ans+MOD)%MOD); return 0; }

Compilation message (stderr)

fish.cpp: In function 'int main()':
fish.cpp:64:8: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%d %d",&N,&K);
   ~~~~~^~~~~~~~~~~~~~~
fish.cpp:65:8: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%d",&MOD);
   ~~~~~^~~~~~~~~~~
fish.cpp:67:10: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
     scanf("%d %d",&fishes[i].size,&fishes[i].gem);
     ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...