zoukankan      html  css  js  c++  java
  • P2943 [USACO09MAR]Cleaning Up G

    一句话题意:将一个数列分成若干段,每段的不和谐度为该段内不同数字数量的平方,求不和谐度之和的最小值。

    (f_i) 表示前 (i) 个数的最小答案,很容易就能写出暴力转移方程:(f_i=min{f_j+sum(j,i)}(0leq j<i))(sum(j,i)) 表示 (jsim i) 中不同数字的数量。

    这样做是 (O(N^2)) 的,考虑优化。发现 (f) 数组是单调不降的,在 (sum(j,i)) 相同时,(j) 取最小最优。继续推性质,发现答案最大是 (N)(每个数都分一段),所以 (sum(j,i)) 最大取 (lfloorsqrt N floor) 否则显然不优。

    然后就很简单了,我们对于 (sum(j,i)) 的每种取值都维护 (j) 的最小值即可。

    所以做题要多推推性质啦。

    时间复杂度 (O(Nsqrt N))

    code:

    #include<bits/stdc++.h>
    using namespace std;
    #define N 40005
    #define Db double
    #define Min(x,y)((x)<(y)?x:y)
    #define For(i,x,y)for(i=x;i<=(y);i++)
    int f[N],last[N],que[205];
    int main()
    {
    	int n,m,top,i,j,p;
    	scanf("%d%d",&n,&m);
    	top=int(sqrt(Db(n)));
    	For(i,1,m)last[i]=-1;
    	For(i,1,n)
    	{
    		f[i]=i;
    		scanf("%d",&p);
    		if(last[p]<que[1])
    		For(j,1,top)que[j-1]=que[j];
    		else
    		{
    			For(j,1,top)
    			if(que[j]==last[p])break;
    			while(j<top)que[j]=que[j+1],j++;
    		}
    		que[top]=i;
    		For(j,1,top)f[i]=Min(f[que[j-1]]+(top-j+1)*(top-j+1),f[i]);
    		last[p]=i;
    	}
    	cout<<f[n];
    	return 0;
    }
    
  • 相关阅读:
    netcore 报错 502 缺少运行时
    简单工厂模式
    net之-------状态模式
    pc端字体正常, 缩放浏览器正常,手机模式查看出问题
    我的后续情况
    [wip]Berty
    利用FileReader对象回显图片
    测试
    CMP云管平台竞标产品
    nacos spring cloud
  • 原文地址:https://www.cnblogs.com/May-2nd/p/13366491.html
Copyright © 2011-2022 走看看