zoukankan      html  css  js  c++  java
  • UOJ#104. 【APIO2014】Split the sequence 动态规划 斜率优化

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ104.html

    题解

    首先证明一个结论:对于一种分割方案,分割的顺序不影响最终结果。

    证明:对于树 a[x] 和 a[y] ,如果 x 与 y 之间有分割,那么它们对答案的贡献就是 a[x] * a[y] ,否则无贡献。

    于是问题转化成 DP: 设 dp[i][j] 表示把前 j 个数分成 i 段的最大收益,那么:

    设 

    $$s[k] = sum_{i=1}^{k} a[i]$$

    $$dp[i][j] = max_{0leq k<j}(dp[i-1][k] + (s[j] - s[k])s[k])$$

    直接斜率优化即可。

    代码

    #include <bits/stdc++.h>
    #define clr(x) memset(x,0,sizeof (x))
    #define For(i,a,b) for (int i=a;i<=b;i++)
    #define Fod(i,b,a) for (int i=b;i>=a;i--)
    #define pb(x) push_back(x)
    #define mp(x,y) make_pair(x,y)
    #define fi first
    #define se second
    #define real __zzd001
    #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
    #define outval(x) printf(#x" = %d
    ",x)
    #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
    #define outtag(x) puts("----------"#x"----------")
    #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);
    						For(_v2,L,R)printf("%d ",a[_v2]);puts("");
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector <int> vi;
    LL read(){
    	LL x=0,f=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		f|=ch=='-',ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return f?-x:x;
    }
    const int N=100005,K=205;
    const LL INF=1e18;
    int n,k;
    int a[N],s[N];
    LL dp[K][N];
    int pre[K][N];
    LL x[N],y[N];
    int q[N],head,tail;
    double pos(int a,int b){
    	return (double)(x[a]-x[b])/(y[b]-y[a]);
    }
    void Push(int i,int j){
    	if (dp[i][j]>=0){
    		x[j]=dp[i][j]-(LL)s[j]*s[j];
    		y[j]=s[j];
    		while (head<=tail&&y[j]==y[q[tail]]){
    			if (x[j]<=x[q[tail]])
    				return;
    			tail--;
    		}
    		while (head<tail&&pos(q[tail],j)<=pos(q[tail-1],q[tail]))
    			tail--;
    		q[++tail]=j;
    	}
    }
    int main(){
    	n=read(),k=read()+1;
    	For(i,1,n)
    		a[i]=read(),s[i]=s[i-1]+a[i];
    	For(i,0,K-1)
    		For(j,0,N-1)
    			dp[i][j]=-INF;
    	dp[0][0]=0;
    	For(i,1,k){
    		head=1,tail=0;
    		clr(x),clr(y);
    		Push(i-1,0);
    		For(j,1,n){
    			while (head<tail&&pos(q[head],q[head+1])<=s[j])
    				head++;
    			if (head<=tail){
    				dp[i][j]=x[q[head]]+y[q[head]]*s[j];
    				pre[i][j]=q[head];
    			}
    			Push(i-1,j);
    		}
    	}
    	cout<<dp[k][n]<<endl;
    	int x=pre[k][n];
    	while (--k)
    		printf("%d ",x),x=pre[k][x];
    	return 0;
    }
    /*
    dp[i][j] = max_{0<=k<j}(dp[i-1][k] + (s[j] - s[k]) * s[k])
    dp[i][j] = max_{0<=k<j}(dp[i-1][k] - s[k] * s[k] + s[j] * s[k])
    */
    

      

  • 相关阅读:
    Linux 查看内存状态
    Linux sar工具安装使用
    DNS ARP地址解析原理
    TCP/UDP 端口
    TCP/IP 传输原理
    Window vagrant 安装部署【转】
    Window7下vagrant的部署
    Ubuntu下访问SSH
    使用 Vagrant 打造跨平台开发环境
    Vagrant入门[转]
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ104.html
Copyright © 2011-2022 走看看