1. 程式人生 > 其它 >CF786C Till I Collapse

CF786C Till I Collapse

題目分析

首先,對於這道題,可以用貪心以一個\(O(n)\)的複雜度求解一個\(k\)的值

暴力是\(O(n^2)\)的複雜度,當然過不了。

我們手推一下樣例,會發現,答案滿足單調性,於是,果斷想到二分。

再推一推性質,會發現,實際上,一個答案最多會出現\(\sqrt n\)次,於是,可以對答案分塊,用二分列舉右邊界,時間複雜度\(O(n\sqrt nlog(n))\),還是過不了。

但因為每一次一個答案最多會出現\(\sqrt n\)次,這就是塊的最大長度。

於是,對於\(k\le\sqrt n\)的部分,可以暴力,最後,卡卡常就過了。

對於每一個數,可以記錄出現的最大塊,看是否在當前塊出現,這樣就避免了在算 \(k\)

時多出一個清空陣列的時間複雜度

#include<bits/stdc++.h>
using namespace std;
int n;
int a[100005];
int tot[100005]; 
int size;
int check(int mid)
{
	int now=1;
	int cout=0;
	for(int i=1;i<=n;i++)
	{
		if(tot[a[i]]!=now)
		{
			cout++;
			tot[a[i]]=now;
		}
		if(cout>mid)
		{
			cout=1;
			now++;
			tot[a[i]]=now;
		}
	}
	return now; 
}
int main()
{
	scanf("%d",&n);
	size=sqrt(n*log2(n));
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=size;i++)
	{
		int now=1;
		int cout=0;
		memset(tot,0,sizeof(tot));
		for(int j=1;j<=n;j++)
		{
			if(tot[a[j]]!=now)
			{
				cout++;
				tot[a[j]]=now;
			}
			if(cout>i)
			{
				cout=1;
				now++;
				tot[a[j]]=now;
			}
		}

		printf("%d ",now);
	}
	int l=size+1;
	int r;
	while(l<=n)
	{
		int now=1;
		int cout=0;
		memset(tot,0,sizeof(tot));
		for(int i=1;i<=n;i++)
		{
			if(tot[a[i]]!=now)
			{
				cout++;
				tot[a[i]]=now;
			}
			if(cout>l)
			{
				cout=1;
				now++;
				tot[a[i]]=now;
			}
		}
		int L=l;
		int R=n;
		while(L<=R)
		{
			int mid=(L+R)>>1;
			memset(tot,0,sizeof(tot));
			int tc=check(mid);
			if(tc>=now)
			{
				L=mid+1;
				r=mid;
			}
			else
			{
				R=mid-1;
			}
		}
		for(int i=l;i<=r;i++)
		{
			printf("%d ",now);
		}
		l=r+1;
	}
}