Loading [MathJax]/jax/output/HTML-CSS/jax.js


Codechef CHSIGN Change the Signs(May Challenge 2018) 动态规划

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

题目传送门 - Codechef CHSIGN

题意

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

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

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

  T,n105, n5×105, ai109

题解

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

  si>si2    (i=2)

  si>si2si>si3   (2<in)

  而且,显然,被修改的ai必然满足ai<ai1, ai<ai+1(当i=1i=n的时候稍微特殊)。

  设dpi为处理了a1i且修改了ai时,保证前i个元素构成的子序列合法,a1i的最大值。

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

dpi=min(dpjsj+si2ai)(这里的sa被修改之前的s,不要和之前提到的s混淆,后面的也要注意。)

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

  对于i,满足ai<ai1, ai<ai+1

  于是第i1个元素不能被修改,故j<i1

  当j=i2时,需要满足ai2+ai1ai>0

  当j<i2时,由于ai<ai1, ai<ai+1,所以si>si2, si>si3si+1>si1, si+1>si2(太显然了,自己验证)。所以只要j<i2就可以转移。于是我们只需要对dpjsj取个前缀min即可。

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

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#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,显然可以
*/

  

posted @   zzd233  阅读(329)  评论(0编辑  收藏  举报
编辑推荐:
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 数据库服务器 SQL Server 版本升级公告
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)
· 程序员常用高效实用工具推荐,办公效率提升利器!

点击右上角即可分享
微信分享提示