Till I Collapse
题
将n个数划分成连续的m段使得每段中不同数字的个数≤k,对于每个k满足1≤k≤n求出最小的m。
解
分析一下容易发现,k的增大使得答案不增大,即答案具有单调性。
其次,对于k答案不超过n/k,那么不同答案的个数不超过
n
\sqrt{n}
n级别。
于是对于
n
\sqrt{n}
n以内的我们直接暴力找,
n
\sqrt{n}
n以外的找到之外再去二分一块答案相同的部分。
此题略有分块思想,而具体实现则是二分。这里用的是双闭二分。
code
const ll maxn=1e5+5;
ll a[maxn];
bool c[maxn];
ll len;
ll n;
ll work(ll k)
{
memset(c,0,sizeof c);
ll ans=0,cnt=0,last=1;
for(ll i=1;i<=n;i++){
if(!c[a[i]])c[a[i]]=1,cnt++;
if(cnt>k){
ans++,cnt=1;
for(ll j=last;j<i;j++)c[a[j]]=0;
c[a[i]]=1;last=i;
}
}
if(cnt)ans++;
return ans;
}
int main()
{
cin>>n;
for(ll i=1;i<=n;i++)cin>>a[i];
len=sqrt(n);
for(ll i=1;i<=n;i++){
if(i<=len){
cout<<work(i)<<' ';
}
else {
ll ans=work(i);
ll l=i,r=n,mid;
while(l<=r){
mid=(l+r)>>1;
if(work(mid)<ans)r=mid-1;
else l=mid+1;
}
for(ll j=i;j<l;j++)cout<<ans<<' ';
i=l-1;
}
}
cout<<'\n';
//system("pause");
return 0;
}