题意:将n个人分成连续的若干组,每组人的种类不得超过k种,k的范围是[1,n],对每一个k输出最少的组数。
思路:设r[k]为种类不超过k时的最小组数,对于任意k属于[1,n]都有r[ll]>=r[rr],(1<=ll<=rr<=n),则当r[ll]=r[rr]时,[ll,rr]范围内的r[k]相等。
Input
10
4 1 2 6 8 5 3 9 3 9
Output
10 4 3 2 2 2 2 1 1 1
Input
15
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Output
15 8 5 4 3 3 3 2 2 2 2 2 2 2 1
//将n个人分成连续的若干组,每组人的种类不得超过k种,k的范围是[1,n],对每一个k输出最少的组数。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
int n;
int a[100010]; //Input Value
int c[100010];
int r[100010];
/*
功能:返回每组最多k种时的最少组数
c[]:所属组的编号,注意遍历是下标是a[j],而非j;
res:组数
cnt:每组的人数
*/
int f(int k)
{
memset(c,-1,sizeof(c));
int res=0;
int cnt=0;
for(int j=1; j<=n; j++)
{
if(c[a[j]]==res)
continue;
c[a[j]]=res;
cnt++;
if(cnt>k)
{
cnt=1;
res++;
c[a[j]]=res;
}
}
return res+1;
}
/*
功能:求[ll,rr]范围内的k对应的最少组数
r[]:存放最少组数
Note:对于所有的r[]均满足r[rr]<=r[ll],故若r[rr]==r[ll],那么[ll,rr]范围内的数值相等
*/
void Run(int ll,int rr)
{
if(ll>rr)
return ;
r[ll]=f(ll);
r[rr]=f(rr);
if(r[ll]==r[rr])
{
for(int i=ll+1;i<rr;i++)
r[i]=r[ll];
return ;
}
Run(ll+1,(ll+rr)/2);
Run((ll+rr)/2+1,rr-1);
}
int main()
{
while(cin>>n)
{
for(int i=1; i<=n; i++)
cin>>a[i];
Run(1,n);
for(int i=1; i<=n; i++)
printf(i!=n?"%d ":"%d\n",r[i]);
}
return 0;
}