[FROM WOJ]#2428 [USACO09MAR]清理Cleaning Up

#2428 [USACO09MAR]清理Cleaning Up

玄学DP

题面
有N头奶牛,每头牛都有一个标号Pi,1 <= Pi <= M <= N <= 40000。现在Farmer John要把这些奶牛分成若干段,定义每段的不和谐度为:若这段里有k个不同的数,那不和谐度为k*k。那总的不和谐度就是所有段的不和谐度的总和。

输入
第一行:两个整数N,M
第2…N+1行:N个整数代表每个奶牛的编号

输出
一个整数,代表最小不和谐度

样例输入
13 4
1
2
1
3
2
2
3
4
3
4
3
1
4

样例输出
11

SOL
看到题面时,真的很慌——但是慌有什么用呢?于是就开始思考DP方程……(╥╯^╰╥)
最开始当然就很容易想到O(n2)的做法——设f[i]表示前i个数的子问题答案,于是就有了O(n2)的转移:
f[i]=min(f[i],f[j-1]+sum),sum为[i,j]这一段花去的时间,sum也许可以预处理一下;
But,看到4e4的数据,还是冷静了下来,开始想更快的方法……
看到4e4的数据,容易考虑O(nlogn) or O(n1.5) 的做法来维护f[i]的值,于是就开始玄学操作……
首先,先考虑一下最坏情况——如果每个数为一段,那么会有n段,时间为n,显然如果一个划分方法如果使得时间超过n,那么这个划分方法显然不够优美(?),所以只考虑每段的数字种数不超过n0,5的情况,那么第二层循环可以大大优化,维护f[i]的值便愉快地变成了O(n1.5) 。
记录一个pos[j]来表示当前考虑的区间向前最远可以到达、且使[ pos[j],i ]种类数不超过j的地方,于是有了新的状态转移方程:
f[i]=min(f[i],f[pos[j]-1]+j2),(j<=n0.5);
然后会发现维护这个pos[j]的值变成了这道题的核心。维护pos[j]的时候,你会发现你需要更多的值来维护她——因为她需要知道当前的i这个位置的a[i],也就是当前这头奶牛的编号,这个值如果小于i-1那次循环更新后的她,那么也就意味着你需要给她加1(也就是编号种类多了一种),所以需要来维护一个prv[a[i]],即第i头奶牛的a[i]值上一次出现的位置。加了这个1之后有可能使当前区间不只j种,那么维护一个tot[j],表示区间内也多少种编号,于是:if(prv[i]<pos[j])tot[j]++。
那么当tot[j]>j种时,就把pos[j]位置后挪一下就行了,维护一个nxt值,nxt[a[k]]表示的是第k头牛的编号下一次在数列中出现的位置。
当nxt[pos[j]]<i的时候,就++pos[j],然后就没有然后了 ……再注意一下细节,比如prv[i]>=pos[j]就可以不管了。
细节见代码。

代码:

#include<bits/stdc++.h>
#define N 40404
#define inf 0x7ffff
using namespace std;
template <class T>
inline void read(T &x){
	x=0;static char c=getchar();
	while(c<'0'||c>'9')c=getchar();
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
}
int n,m;
int a[N],f[N],pos[202],prv[N],nxt[N],tot[202],las[N];
int main(){
	read(n);read(m);
	for(int register i=1;i<=n;++i){
		read(a[i]);
		prv[i]=las[a[i]];//以i为下标存一个a[i]上一次出现的位置
		nxt[las[a[i]]]=i;
		las[a[i]]=i;//a[i]为下标再存一个,便于下次找
		f[i]=inf;//初始化 
		nxt[i]=n+1;
	}
	int maxl=sqrt(n);
	for(int register i=1;i<=maxl;i++)pos[i]=1;
	for(int register i=1;i<=n;i++){
		for(int register j=1;j<=maxl;j++){
			if(prv[i]<pos[j])tot[j]++;
			if(tot[j]>j){
				tot[j]--;
				while(nxt[pos[j]]<i)pos[j]++;
				pos[j]++;
			}
			f[i]=min(f[i],f[pos[j]-1]+j*j);
		}
	}
	printf("%d",f[n]);return 0;
}

猜你喜欢

转载自blog.csdn.net/hzq_oi/article/details/87184630