Codeforces Round #521 (Div. 3) E. Thematic Contests
题意:
现在有n个题目,每种题目有自己的类型
要举办一次考试,
考试的原则是
每天只有一种题目类型
一种题目类型只能出现在一天
每天的题目类型不能相同,
而且后一天的题目数量必须正好为前一天的两倍,第一天的题目数量是任意的
求怎么安排能使题目尽量多。注意:不是天数尽量多
思路:
首先我们知道一件事,题目属于哪种类型并不重要,重要的是每种类型的个数
所以我们先统计出所有类型的个数,存进一个数组,
而最终最优解一定是按照题目数量从小到大来的,所以我们对该数组进行排序
而我们怎么确定最终怎么选择呢,我们发现最终怎么选择取决于第一天怎么选择
而且只要确定了第一天的题目数。我们要看哪个过程可以优化
第一天的题目数并不满足二分的性质,我们就考虑优化能选就选这个原则
在排好序的数组上我们可以通过lower_bound快速找到>=当前所需数目的下标pos
之后让pos++,继续下一次查找,这样我们最多查找log次就能完成check
于是这道题就是O(n) O(n)O(n)枚举第一天的题目数,O(logn) O(logn)O(logn)check,总复杂度O(nlogn) O(nlogn)O(nlogn)
原文来自:https://blog.csdn.net/qq_38891827/article/details/84149250
代码:
#include<bits/stdc++.h> using namespace std; #define N 200005 int x[N]; map<int,int>mp; int n; int main() { while(~scanf("%d",&n)) { mp.clear(); for(int i=1;i<=n;i++) { int k; scanf("%d",&k); mp[k]++; } map<int,int>::iterator it; int tot=0; for(it=mp.begin();it!=mp.end();it++) { x[tot++]=(*it).second; } sort(x,x+tot); long long ans=0; for(int i=1;i<=n;i++) { long long tmp=0; int pos=0; for(int j=i;j<=n;j*=2) { int t=lower_bound(x+pos,x+tot,j)-x; if(t==tot) break; tmp+=j; pos=t+1; } ans=max(ans,tmp); } printf("%lld ",ans); } return 0; }