洛谷 P1121 环状最大两段子段和

https://www.luogu.org/problemnew/show/P1121

不会做啊。。。

看题解讲的:

答案的两段可能有两种情况:一是同时包含第1和第n个,2是不同时包含第1和第n个

对于第二种可以先求出f[i],g[i]分别表示1..i和i..n的最大子段和,然后枚举断点解决

对于第一种可以转化成找到“序列上最小两段字段和“去掉,这可以用第二种的方法解决;不过注意这个”序列上最小两段字段和“长度必须<=n-2(因为要剩下至少2个元素),需要一些特判

另外,话说此题居然还能用线段树维护...

(然而数据弱,仍然不知道以下代码是不是对的)

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<vector>
  5 using namespace std;
  6 #define fi first
  7 #define se second
  8 #define pb push_back
  9 typedef long long ll;
 10 typedef unsigned long long ull;
 11 #define int ll
 12 struct pii
 13 {
 14     int fi,se;
 15     pii():fi(0),se(0){}
 16     pii(int a,int b):fi(a),se(b){}
 17 };
 18 pii max1(const pii &a,const pii &b)
 19 {
 20     return (a.fi<b.fi||(a.fi==b.fi&&a.se>b.se))?b:a;
 21 }
 22 pii min1(const pii &a,const pii &b)
 23 {
 24     return (a.fi<b.fi||(a.fi==b.fi&&a.se<b.se))?a:b;
 25 }
 26 int a[200010];
 27 pii f1[200010],g1[200010],f2[200010],g2[200010];
 28 int n,a1,a2,sum;
 29 int calc(int p)
 30 {
 31     if(p==1)
 32     {
 33         return g2[2].se==n-1 ? g2[2].fi-max(a[2],a[n]) : g2[2].fi;
 34     }
 35     else if(p==n)
 36     {
 37         return f2[n-1].se==n-1 ? f2[n-1].fi-max(a[1],a[n-1])
 38             : f2[n-1].fi;
 39     }
 40     else
 41     {
 42         return f2[p-1].se+g2[p+1].se==n-1
 43             ? f2[p-1].fi+g2[p+1].fi - max(max(a[1],a[p-1]),
 44                 max(a[p+1],a[n]))
 45             : f2[p-1].fi+g2[p+1].fi;
 46     }
 47 }
 48 signed main()
 49 {
 50     int i;pii t;
 51     scanf("%lld",&n);
 52     if(n<=1)    exit(-1);
 53     for(i=1;i<=n;++i)
 54     {
 55         scanf("%lld",&a[i]);
 56         sum+=a[i];
 57     }
 58     f1[1]=pii(a[1],1);
 59     t=pii(a[1],1);
 60     if(t.fi<=0)    t=pii(0,0);
 61     for(i=2;i<=n;++i)
 62     {
 63         t.fi+=a[i];++t.se;
 64         f1[i]=max1(f1[i-1],t);
 65         if(t.fi<=0)    t=pii(0,0);
 66     }
 67     g1[n]=pii(a[n],1);
 68     t=pii(a[n],1);
 69     if(t.fi<=0)    t=pii(0,0);
 70     for(i=n-1;i>=1;--i)
 71     {
 72         t.fi+=a[i];++t.se;
 73         g1[i]=max1(g1[i+1],t);
 74         if(t.fi<=0)    t=pii(0,0);
 75     }
 76     f2[1]=pii(a[1],1);
 77     t=pii(a[1],1);
 78     if(t.fi>=0)    t=pii(0,0);
 79     for(i=2;i<=n;++i)
 80     {
 81         t.fi+=a[i];++t.se;
 82         f2[i]=min1(f2[i-1],t);
 83         if(t.fi>=0)    t=pii(0,0);
 84     }
 85     g2[n]=pii(a[n],1);
 86     t=pii(a[n],1);
 87     if(t.fi>=0)    t=pii(0,0);
 88     for(i=n-1;i>=1;--i)
 89     {
 90         t.fi+=a[i];++t.se;
 91         g2[i]=min1(g2[i+1],t);
 92         if(t.fi>=0)    t=pii(0,0);
 93     }
 94     a1=f1[1].fi+g1[2].fi;
 95     for(i=2;i<=n-1;++i)
 96         a1=max(a1,f1[i].fi+g1[i+1].fi);
 97     a2=calc(1);
 98     for(i=2;i<=n;++i)
 99         a2=min(a2,calc(i));
100     printf("%lld",max(a1,sum-a2));
101     return 0;
102 }
View Code

 

posted @ 2018-10-28 15:36  hehe_54321  阅读(214)  评论(0编辑  收藏  举报
AmazingCounters.com