Submission #132051

#TimeUsernameProblemLanguageResultExecution timeMemory
132051dragonslayeritFish (IOI08_fish)C++14
38 / 100
3052 ms10132 KiB
#include <cstdio>
#include <algorithm>

//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 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];

int main(){
  int N,K,MOD;
  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;
    //printf("prev[%d]=%d\n",i,prev[i]);
  }
  /*
    for(int i=0;i<N;i++){
    printf("i=%d size=%d gem=%d\n",i,fishes[i].size,fishes[i].gem);
    }
  */

  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
    //for(int& j=half[k]=0;fishes[j].size*2<=fishes[last[k]].size;j++);
  }
  
  int ans=0;
  int prefix=K-1;//largest gem # that can be "boosted"
  for(int i=0;i<N;i++){
    freq[fishes[i].gem]++;
    while(prefix>=0&&fishes[last[prefix]].size<2*fishes[i].size) prefix--;
    //printf("i=%d boostable gem prefix=[0,%d]\n",i,prefix);
    //Counting configurations where fishes[i].gem occurs exactly freq[fishes[i].gem] times
    //Subtract multisets where none in prefix exist to be boosted
    {
      int product=1;
      for(int k=prefix+1;k<K;k++){
	if(k==fishes[i].gem) continue;
	product=1LL*product*(freq[k]+1)%MOD;
      }
      ans=(ans+MOD-product)%MOD;
    }
    //Add back multisets where none in prefix exist to be boosted but fishes[i] can be boosted
    //using frequencies from last fish whose size <=1/2*size of last fish with fishes[i].gem

    if(prev[i]!=-1&&fishes[prev[i]].size*2>fishes[last[fishes[i].gem]].size){
      //printf("SKIP %d\n",i);
      continue;
    }
    
    {
      std::fill(freq2,freq2+K,0);
      for(int j=0;j<std::min(i,half[fishes[i].gem]);j++){
	freq2[fishes[j].gem]++;
      }
      /*
	if(freq2[fishes[i].gem]!=freq[fishes[i].gem]-1){
	  printf("SKIP %d\n",i);
	  continue;
	}
      */
      int product=1;
      for(int k=prefix+1;k<K;k++){
	if(k==fishes[i].gem) continue;
	product=1LL*product*(freq2[k]+1)%MOD;
      }
      //printf("\n");
      ans=(ans+product)%MOD;
      //printf("i=%d, j=%d: Add %d\n",i,j,product);
    }
  }
  //Count all multisets and subtract bad ones
  int all=1;
  for(int k=0;k<K;k++){
    all=1LL*all*(freq[k]+1)%MOD;
  }
  //-1 for empty set
  ans=(ans+all+MOD-1)%MOD;
  printf("%d\n",ans);
  return 0;
}

Compilation message (stderr)

fish.cpp: In function 'int main()':
fish.cpp:31: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:32:8: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%d",&MOD);
   ~~~~~^~~~~~~~~~~
fish.cpp:34: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...