zoukankan      html  css  js  c++  java
  • BZOJ2288: 【POJ Challenge】生日礼物

    2288: 【POJ Challenge】生日礼物

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 284  Solved: 82
    [Submit][Status]

    Description

    ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, ..., AN. 她被允许选择不超过 M 个连续的部分作为自己的生日礼物。

    自然地,ftiasch想要知道选择元素之和的最大值。你能帮助她吗?


    Input

    第1行,两个整数 N (1 ≤ N ≤ 105) 和 M (0 ≤ M ≤ 105), 序列的长度和可以选择的部分。

    第2行, N 个整数 A1, A2, ..., AN (0 ≤ |Ai| ≤ 104), 序列。

    Output

     

    一个整数,最大的和。

    Sample Input


    5 2
    2 -3 2 -1 2

    Sample Output

    5

    HINT

    Source

    题解:

    感觉和数据备份这题有点像,但是又转化不过来。。。看了hzwer的题解之后恍然大悟了。。。

    首先连在一块的正负相同的肯定可以看成一个点,然后我们就得到了一个正负交替的数列,并且首位两项都是正数(负数去掉)

    然后如果正的项数<=m,那显然我们全部选走就获得了最大权值,否则我们需要做一点牺牲。

    1)不选某些正项

    2)选一些负项使得相邻的正项成为1块

    记所有正数之和为sum,我们需要进行上面两种操作使得sum减掉的数最小并且满足只有m块。

    我们把所有数的绝对值放入一个堆,每次取最小元素x。sum'-=x

    那么如果该数原来是正的,意思是不选它;

    如果是负的,意思是把它两边的正数合并。

    但直接这样做是不行的,我们必须保证取负的时候两边的正的必须不被取,取正的时候两边的负的不被取。

    换句话说,不能选择相邻的两个数!我们成功的将此题转化成了数据备份问题。

    orz!

    代码:

     1 #include<cstdio>
     2 
     3 #include<cstdlib>
     4 
     5 #include<cmath>
     6 
     7 #include<cstring>
     8 
     9 #include<algorithm>
    10 
    11 #include<iostream>
    12 
    13 #include<vector>
    14 
    15 #include<map>
    16 
    17 #include<set>
    18 
    19 #include<queue>
    20 
    21 #include<string>
    22 
    23 #define inf 1000000000
    24 
    25 #define maxn 100000+5
    26 
    27 #define maxm 500+100
    28 
    29 #define eps 1e-10
    30 
    31 #define ll long long
    32 
    33 #define pa pair<int,int>
    34 
    35 #define for0(i,n) for(int i=0;i<=(n);i++)
    36 
    37 #define for1(i,n) for(int i=1;i<=(n);i++)
    38 
    39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
    40 
    41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
    42 
    43 #define mod 1000000007
    44 
    45 using namespace std;
    46 
    47 inline int read()
    48 
    49 {
    50 
    51     int x=0,f=1;char ch=getchar();
    52 
    53     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    54 
    55     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
    56 
    57     return x*f;
    58 
    59 }
    60 int n,k,s,t,ans,a[maxn],b[maxn],l[maxn],r[maxn];
    61 priority_queue<pa,vector<pa>,greater<pa> >q;
    62 
    63 int main()
    64 
    65 {
    66 
    67     freopen("input.txt","r",stdin);
    68 
    69     freopen("output.txt","w",stdout);
    70 
    71     t=read();k=read();
    72     for1(i,t)a[i]=read();while(a[t]<=0)t--;
    73     s=1;while(a[s]<=0)s++;
    74     for(;s<=t;s++)if((a[s]>0&&a[s-1]>0)||(a[s]<=0&&a[s-1]<=0))b[n]+=a[s];else b[++n]=a[s];
    75     for1(i,n)if(b[i]>0){ans+=b[i];k--;}else b[i]=-b[i];
    76     if(k>=0){cout<<ans<<endl;return 0;}
    77     for1(i,n)l[i]=i-1,r[i]=i+1,q.push(pa(b[i],i));
    78     r[n]=0;
    79     for1(i,abs(k))
    80     {
    81       while(b[q.top().second]!=q.top().first)q.pop();
    82       int x=q.top().second;q.pop();
    83       ans-=b[x];
    84       if(!l[x]){b[r[x]]=inf;l[r[x]]=0;}
    85       else if(!r[x]){b[l[x]]=inf;r[l[x]]=0;}
    86       else 
    87       {
    88           b[x]=b[l[x]]+b[r[x]]-b[x];
    89           b[l[x]]=b[r[x]]=inf;
    90           r[l[x]=l[l[x]]]=l[r[x]=r[r[x]]]=x;
    91           q.push(pa(b[x],x));
    92       }
    93     }
    94     cout<<ans<<endl;
    95 
    96     return 0;
    97 
    98 } 
    View Code

    还有一点,之所以赋删去的点的权值为inf是为了不用手打堆,erase233

  • 相关阅读:
    单点登陆的javascript类原创
    goole图标
    字符串string的相关应用
    今天心情好,发首我喜欢的歌天黑黑
    爱情幸福!
    linux虚拟实现
    页面显示的问题
    由我们MIS的老师,所引发的一点感想.
    有关PERL5和正则表达式
    本来没有什么好说的!
  • 原文地址:https://www.cnblogs.com/zyfzyf/p/4114774.html
Copyright © 2011-2022 走看看