Codeforces 1077D Cutting Out(二分答案)
题目链接:Cutting Out
题意:给定一个n长度的数字序列s,要求得到一个k长度的数字序列t,每次从s序列中删掉完整的序列t,求出能删次数最多的那个数字序列t。
题解:数字序列s先转换成不重复的数字序列,并记录各个数字重复的次数,然后按照重复次数从大到小排序。二分最大删除次数,最后再输出对应的序列t。
1 #include <map> 2 #include <cstdio> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 const int N=2e5+10; 8 int n,k,x,id=0; 9 map <int,int> m; 10 struct node{ 11 int val,cnt; 12 }p[N]; 13 14 bool cmp(node x,node y){ 15 return x.cnt>y.cnt; 16 } 17 18 bool check(int mid){ 19 int need=k; 20 for(int i=1;i<=id;i++){ 21 if(need==0) return true; 22 int tmp=p[i].cnt/mid; 23 if(tmp>=1){ 24 if(need>=tmp) need-=tmp; 25 else return true; 26 } 27 else return false; 28 } 29 if(need>0) return false; 30 return true; 31 } 32 33 int main(){ 34 scanf("%d%d",&n,&k); 35 for(int i=1;i<=n;i++){ 36 scanf("%d",&x); 37 if(!m[x]) id++,m[x]=id,p[id].val=x; 38 p[m[x]].cnt++; 39 } 40 sort(p+1,p+1+id,cmp); 41 int l=1,r=N,ans=1; 42 while(l<=r){ 43 int mid=(l+r)/2; 44 if(check(mid)) l=mid+1,ans=mid; 45 else r=mid-1; 46 } 47 for(int i=1;i<=id;i++){ 48 if(k==0) break; 49 int tmp=p[i].cnt/ans; 50 if(tmp>=1){ 51 if(k>=tmp){ 52 k-=tmp; 53 for(int j=1;j<=tmp;j++) printf("%d ",p[i].val); 54 } 55 else{ 56 for(int j=1;j<=k;j++) printf("%d ",p[i].val); 57 k=0; 58 } 59 } 60 } 61 return 0; 62 }