zoukankan      html  css  js  c++  java
  • 题解「CSP2019 划分」

    (f_i)(1sim n) 划分成若干段得到的最小值,(g_i)(f_i) 转移过来的决策值。

    什么意思呢?我们有 ( ext{DP}) 转移方程:

    [f_i=min{f_j+(sum_i-sum_j)^2}(g_jleq sum_i-sum_j) ]

    那么 (g_i) 就为令上式取到最小值的 (sum_i-sum_j)

    这样就有了一个 (O(n^2)) 的做法,能够获得 (64 ext{pts})

    我们发现上式的约束可以改写为 (g_j+sum_jleq sum_i),又发现 (sum_i) 是单增的,这使我们想到用单调队列维护。正确性基于,最后一段我们希望它尽可能的小。于是时间复杂度优化为 (O(n))

    只能获得 (88 ext{pts}),由于没有高精/kk

    #include<cstdio>
    #define int ll
    typedef long long ll;
    int f[1000005],g[1000005],a[1000005],q[1000005];
    inline int read() {
    	register int x=0,f=1;register char s=getchar();
    	while(s>'9'||s<'0') {if(s=='-') f=-1;s=getchar();}
    	while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    	return x*f;
    } 
    signed main() {
    	int n=read(),type=read();
    	for(register int i=1;i<=n;++i) a[i]=a[i-1]+read();
    	int hd=0,tl=0; 
    	for(register int i=1;i<=n;++i) {
    		while(hd<tl&&a[q[hd+1]]+g[q[hd+1]]<=a[i]) ++hd;//g[q[hd+1]]<=a[i]-a[q[hd+1]]
    		g[i]=a[i]-a[q[hd]]; f[i]=f[q[hd]]+g[i]*1ll*g[i];
    		while(hd<=tl&&a[q[tl]]+g[q[tl]]>=a[i]+g[i]) --tl;
    		q[++tl]=i;
    	}
    	printf("%lld
    ",f[n]);
    	return 0;
    }
    
  • 相关阅读:
    linux 安装软件的方式
    git 基本操作
    交叉编译
    windows下 打印机打印操作类 VS2015
    VS2015 下 unicode 字符转换类
    C++ 多线程日志类的使用
    编译模板实例化
    C++中如何使用switch字符串
    linux下静态库与动态库
    jsoncpp 解码编码 中文为空 乱码问题
  • 原文地址:https://www.cnblogs.com/tommy0103/p/14065147.html
Copyright © 2011-2022 走看看