把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P2943 [USACO09MAR]Cleaning Up G

题面传送门
显然可以\(dp\)
\(n^2\)暴力\(dp\)很好想,循环时直接更新答案即可。
考虑优化。
显然,如果每\(1\)头牛都分成\(1\)组,那么代价为\(n\),所以我们每次枚举状态时种类不能超过\(\sqrt n\),否则为无用转移。
\(\sqrt n\)种类数之内的最左端点怎么搞呢?
显然可以尺取法。跑\(\sqrt n\)趟尺取即可。
时间复杂度\(O(n\sqrt n)\)
代码实现:

#include<cstdio>
#include<cmath>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,f[100039],dp[100039],l[439],tot[439],s[239][100039],a[100039];
int main(){
	register int i,j;
	scanf("%d%d",&n,&m);
	k=sqrt(n);
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
	for(i=1;i<=n;i++){
		dp[i]=1e9;
		for(j=1;j<=k;j++){
			s[j][a[i]]++;
			tot[j]+=(s[j][a[i]]==1?1:0);
			while(tot[j]>j){
				s[j][a[l[j]+1]]--;
				tot[j]-=(s[j][a[l[j]+1]]==0?1:0);
				l[j]++;
			}
			//printf("%d ",tot[j]);
			dp[i]=min(dp[i],dp[l[j]]+j*j);
		}
		//printf("%d\n",dp[i]);
	}
	printf("%d\n",dp[n]);
}
posted @ 2020-05-30 21:41  275307894a  阅读(39)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end