洛谷 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 }