C. Pinkie Pie Eats Patty-cakes (662 div2 构造)

C. Pinkie Pie Eats Patty-cakes

题意: 有 n 个已知种类的蛋糕,求如何吃掉这 n 个蛋糕使得,相同种类的蛋糕之间的蛋糕距离最大,求最大吃法中的相同蛋糕的最小距离(两个相同蛋糕之间的距离为其之间的蛋糕数)。
思路: 所以,如何构造才能使得相同蛋糕之间的距离最大呢,我们把种类最多的蛋糕数设为 k 个 ,显然分开放后会产生k-1个间隔,所以我们把剩下的蛋糕分别填充这k-1个间隙,然后找个最小的距离即可。
注意 :k 可能会出现多个。

Code1:
隔板思想。

#include
using namespace std;
const int N = 1e6+7;

int vis[N];

int main()
{
	int T;cin>>T;
	while(T--){
		int n,t,k=0;
		cin>>n;
		for(int i=1;i<=n;i++) vis[i]=0;
		for(int i=0;i<n;i++){
			scanf("%d",&t);
			k = max(k,++vis[t]);
		}
		if(k==1) {
			printf("%d\n",n-1);continue;
		}
		int num=0;
		for(int i=1;i<=n;i++) if(vis[i]==k) num++;
		printf("%d\n",(n-num*k)/(k-1)+num-1);
	}
	return 0;
}

Code2:

二分答案(间距),check 时判断是否把所有蛋糕安置在n个位置。其构造结果是和 code1 一致的。

#include
using namespace std;
const int N = 1e6+7;

int vis[N],n;
vector<int> ve;
int num;

bool check(int k)
{
	int s = 1;
	for(int i=0;i<num;i++){
		int t = ve[i];
		for(int j=s;j<=n&&t;j += k+1) t--;
		if(t) return 0;
		s++;
	}
	return 1;
}

int main()
{
	int T;cin>>T;
	while(T--){
		int t;
		cin>>n;
		ve.clear();
		for(int i=0;i<n;i++){
			scanf("%d",&t);
			vis[t]++;
		}
		for(int i=1;i<=n;i++) if(vis[i]) ve.push_back(vis[i]),vis[i]=0;
		sort(ve.begin(),ve.end(),greater<int>());
		num = ve.size();
		if(num==1){
			printf("0\n");continue;
		}
		int l=0,r=n;
		while(l<=r){
			int mid = l+r>>1;
			if(check(mid)) l = mid + 1;
			else r = mid - 1; 
		}
		printf("%d\n",l-1);
	}
	return 0;
}

你可能感兴趣的:(CF,二分)