zoukankan      html  css  js  c++  java
  • Codechef CHSIGN Change the Signs(May Challenge 2018) 动态规划

    原文链接http://www.cnblogs.com/zhouzhendong/p/9004583.html

    题目传送门 - Codechef CHSIGN

    题意

      第一行,一个数$T$,表示数据组数。

      对于每一组数据,给定一个$n$,接下来是一个长度为$n$的数列$a$,$a$的第$i$项为$a_i$。

      所有$a_i$都是正整数。现在你可以选择若干个不同的$a_i$使他取相反数,但是你需要保证修改后的序列的任意一段长度大于$1$的连续自序列的数字总和都为正数。在满足条件的基础上,最小化修改之后$sum_{i=1}^n a_i$,并输出方案。

      $T,nleq 10^5, sum n leq 5 imes 10^5, a_ileq 10^9$

    题解

      对操作之后的序列求前缀和之后,我们可以得出以下结论:

      $s_i>s_{i-2} (i=2)$

      $s_i>s_{i-2}且s_i>s_{i-3} (2<ileq n)$

      而且,显然,被修改的$a_i$必然满足$a_i>a_{i-1}, a_i>a_{i+1}$(当$i=1或i=n$的时候稍微特殊)。

      设$dp_i$为处理了$a_{1cdots i}$且修改了$a_i$时,保证前$i$个元素构成的子序列合法,$sum a_{1cdots i}$的最大值。

      先不考虑转移条件,列出转移方程:

    $$dp_i=min(dp_j-s_j+s_i-2a_i)$$(这里的$s$指$a$被修改之前的$s$,不要和之前提到的$s$混淆,后面的也要注意。)

      然后我们来罗列一下条件:

      对于$i$,满足$a_i>a_{i-1}, a_i>a_{i+1}$。

      于是第$i-1$个元素不能被修改,故$j<i-1$。

      当$j=i-2$时,需要满足$-a_{i-2}+a_{i-1}-a{i}>0$。

      当$j<i-2$时,由于$a_i>a_{i-1}, a_i>a_{i+1}$,所以$s_{i}>s_{i-2}, s_{i}>s_{i-3}$且$s_{i+1}>s_{i-1}, s_{i+1}>s_{i-2}$(太显然了,自己验证)。所以只要$j<i-2$就可以转移。于是我们只需要对$dp_j-s_j$取个前缀$min$即可。

      至于求方案这个没什么思维含量就不说了。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=100005;
    const LL INF=1LL<<57;
    int T,n;
    LL a[N],s[N],dp[N],f[N],Min[N];
    LL cc(int i){
    	return dp[i]-s[i];
    }
    int main(){
    	scanf("%d",&T);
    	while (T--){
    		scanf("%d",&n);
    		for (int i=1;i<=n;i++)
    			scanf("%lld",&a[i]),s[i]=s[i-1]+a[i];
    		a[n+1]=INF;
    		LL ans=0;
    		dp[0]=0;
    		dp[1]=a[2]>a[1]?-a[1]:a[1];
    		Min[0]=0;
    		Min[1]=cc(1)<cc(0)?1:0;
    		for (int i=1;i<=n;i++){
    			if (i>=2){
    				dp[i]=INF;
    				if (a[i]<a[i-1]&&a[i]<a[i+1]){
    					if (-a[i-2]+a[i-1]-a[i]>0)
    						if (dp[i-2]+s[i]-s[i-2]-2*a[i]<dp[i]){
    							dp[i]=dp[i-2]+s[i]-s[i-2]-2*a[i];
    							f[i]=i-2;
    						}
    					if (i-3>=0)
    						if (cc(Min[i-3])+s[i]-2*a[i]<dp[i]){
    							dp[i]=cc(Min[i-3])+s[i]-2*a[i];
    							f[i]=Min[i-3];
    						}
    				}
    				Min[i]=cc(Min[i-1])>cc(i)?i:Min[i-1];
    			}
    			if (dp[i]+s[n]-s[i]<dp[ans]+s[n]-s[ans])
    				ans=i;
    		}
    		for (int i=ans;i;i=f[i])
    			a[i]=-a[i];
    		for (int i=1;i<=n;i++)
    			printf("%lld ",a[i]);
    		puts("");
    	}
    	return 0;
    }
    /*
    dp[i]=min(dp[j]+s[i]-s[j]-2*a[i])
    	a[i]<a[i-1],a[i]<a[i+1]
    	j==i-2,-a[i-2]+a[i-1]-a[i]>0
    	j<i-2,显然可以
    */
    

      

  • 相关阅读:
    Thrift官方安装手冊(译)
    从用python做zoj1011发生Non-zero Exit Code错误说起
    POJ 1637 Sightseeing tour(最大流)
    js中substr与substring的差别
    白话经典算法系列之七 堆与堆排序
    在基于阿里云serverCentOS6.5下安装Subversion 1.6.5服务
    Android研究之手PullToRefresh(ListView GridView 下拉刷新)使用具体解释
    java中获取系统属性以及环境变量
    sql中 in 、not in 、exists、not exists 使用方法和区别
    80x86汇编小站站长简单介绍-2014年08月23日
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/CC-CHSIGN.html
Copyright © 2011-2022 走看看