题解:dp[j][i]表示前i个数分了j块,pos[j][i]表第j块的起始位置在哪(即在哪个地方插入一个隔板)。
转移方程: ①dp[j][i]可以从dp[j][i-1]转移过来,表示当前i这个位置的值贡献不是最优。
②dp[j][i]从前面某个值相同的位置转移过来。对于值相同的的位置,可以再开一个数组ans[],与anspos[]分别记录最优值,与相应的最优值的位置。对于一个数值第一次出现而前面可能未预处理,所以每次预处理在dp前面。
#include"bits/stdc++.h"
using namespace std;
const int MX = 1e5+7;
const int INF = 1e9;
map<int,int> mp;
vector<int> res;
int a[MX];
int ans[MX], posans[MX];
int vis[MX], cnt[MX];
int dp[101][MX],pos[101][MX];
void upd(int &dp, int d, int &pos, int po)
{
if(d > dp){
dp = d;
pos = po;
}
}
int main()
{
#ifdef LOCAL
freopen("input.txt","r",stdin);
#else
freopen("funny.in","r",stdin);
freopen("funny.out","w",stdout);
#endif // LOCAL
int n,k;
while(~scanf("%d%d",&n,&k)){
if(n == 0 || k == 0) break;
mp.clear();
res.clear();
int id = 0;
for(int i = 1,x; i <= n; i++){
scanf("%d",&x);
if(mp.count(x)){
a[i] = mp[x];
vis[i] = ++cnt[mp[x]];
continue;
}
a[i] = mp[x] = ++id;
vis[i] = cnt[id] = 1;
}
for(int j = 1; j <= k; j++){
for(int i = 0; i <= id; i++)
ans[i] = -INF;
int x = a[j];
upd(ans[x],dp[j-1][j-1]-vis[j]+1, posans[x],j-1);
dp[j][j] = j;
pos[j][j] = j-1;
for(int i = j+1; i <= n; i++){
int x = a[i];
dp[j][i] = dp[j][i-1];
pos[j][i] = pos[j][i-1];
upd(ans[x],dp[j-1][i-1]-vis[i]+1, posans[x],i-1);
upd(dp[j][i],vis[i]+ans[x], pos[j][i],posans[x]);
// cout<<j<<" "<<i<<" "<<dp[j][i]<<" "<<pos[j][i]<<endl;
}
}
int p = pos[k][n];
for(int j = k-1; j >= 1; j--){
res.push_back(p);
p = pos[j][p];
}
printf("%d\n",dp[k][n]);
for(int i = res.size()-1; i >= 0; i--)
printf("%d%c",res[i]," \n"[i==0]);
}
return 0;
}