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,显然可以
    */
    

      

  • 相关阅读:
    jQuery 源码解析(二十四) DOM操作模块 包裹元素 详解
    jQuery 源码解析(二十三) DOM操作模块 替换元素 详解
    jQuery 源码解析(二十二) DOM操作模块 复制元素 详解
    jQuery 源码分析(二十一) DOM操作模块 删除元素 详解
    jQuery 源码分析(二十) DOM操作模块 插入元素 详解
    jQuery 源码分析(十九) DOM遍历模块详解
    python 简单工厂模式
    python 爬虫-协程 采集博客园
    vue 自定义image组件
    微信小程序 image组件坑
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/CC-CHSIGN.html
Copyright © 2011-2022 走看看