题意:10^5的数列,让你交换两个数,使得交换后的数列的连续区间最大和最大。
分析:我们假设最优解是交换u 和 v,u >= v,那么交换后的最优解应该是以交换后u向左右两端分别扩展的一段区间,和u之前位置异侧的最大扩展值可以O(n)的DP预处理出来,然后我们考虑和u之前位置(也就是v现在的位置)同侧的最大扩展区间,可以证明在原数列中u一定是这个扩展区间终点再往后/前的最大值,所以我们考虑枚举交换后u的位置,然后枚举交换前同侧扩展区间再加上扩展区间往后最大值的和的最大值,这部分可以用线段树优化,总复杂度n*logn,这题一开始贪心的做WA了很久,代码写的巨丑。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
const int INF = 1e9+10;
typedef long long ll;
typedef pair<ll,int> pii;
int n,x,y,a[N];
ll ans,pre[N],suc[N],pre_lab[N],suc_lab[N],pref[N],sucf[N],pref_lab[N],sucf_lab[N];
struct Tree
{
pii val;
ll lazy;
}tr[4*N];
void push_up(int u)
{
int ls = 2*u,rs = 2*u+1;
tr[u].val = max(tr[ls].val,tr[rs].val);
}
void push_down(int u)
{
int ls = 2*u,rs = 2*u+1;
tr[ls].val.first += tr[u].lazy,tr[rs].val.first += tr[u].lazy;
tr[ls].lazy += tr[u].lazy,tr[rs].lazy += tr[u].lazy;
tr[u].lazy = 0;
}
void Build(int u,int l,int r)
{
tr[u].lazy = 0;
if(l == r)
{
tr[u].val = make_pair(0ll,l);
return;
}
int mid = (l+r)>>1;
Build(2*u,l,mid);
Build(2*u+1,mid+1,r);
push_up(u);
}
void add(int u,int l,int r,int x,int y,ll v)
{
if(l == x && r == y)
{
tr[u].val.first += v;
tr[u].lazy += v;
return;
}
push_down(u);
int mid = (l+r)>>1;
if(y <= mid) add(2*u,l,mid,x,y,v);
else
if(x <= mid)
{
add(2*u,l,mid,x,mid,v);
add(2*u+1,mid+1,r,mid+1,y,v);
}
else add(2*u+1,mid+1,r,x,y,v);
push_up(u);
}
pii query(int u,int l,int r,int x,int y)
{
if(l == x && r == y) return tr[u].val;
push_down(u);
int mid = (l+r)>>1;
if(y <= mid) return query(2*u,l,mid,x,y);
else
if(x <= mid)return max(query(2*u,l,mid,x,mid),query(2*u+1,mid+1,r,mid+1,y));
else return query(2*u+1,mid+1,r,x,y);
}
void update(ll val,int l,int r)
{
if(val > ans)
{
ans = val;
x = l;
y = r;
}
}
int main()
{
ans = -INF;
scanf("%d",&n);
for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
pre[0] = suc[n+1] = -INF;
for(int i = 1;i <= n;i++)
{
pre[i] = pre[i-1];
pre_lab[i] = pre_lab[i-1];
if(pre[i] < a[i])
{
pre[i] = a[i];
pre_lab[i] = i;
}
}
for(int i = n;i;i--)
{
suc[i] = suc[i+1];
suc_lab[i] = suc_lab[i+1];
if(suc[i] < a[i])
{
suc[i] = a[i];
suc_lab[i] = i;
}
}
for(int i = 1;i <= n;i++)
{
if(pref[i-1] > 0) pref[i] = pref[i-1] + a[i];
else
{
pref[i] = a[i];
pref_lab[i] = i;
}
}
for(int i = n;i;i--)
{
if(sucf[i+1] > 0)
{
sucf[i] = sucf[i+1] + a[i];
sucf_lab[i] = sucf_lab[i+1];
}
else
{
sucf[i] = a[i];
sucf_lab[i] = i;
}
}
for(int i = 1;i <= n;i++) update(sucf[i],sucf_lab[i],i);
if(pre[n] > 0)
{
Build(1,1,n);
for(int i = n;i;i--)
{
add(1,1,n,i,i,max(suc[i+1],0ll));
if(i != n)
{
pii t = query(1,1,n,i,n);
update(t.first + pref[i] - a[i],i,suc[t.second+1] > 0 ? suc_lab[t.second+1] : t.second);
}
add(1,1,n,i,n,a[i]);
}
Build(1,1,n);
for(int i = 1;i <= n;i++)
{
add(1,1,n,i,i,max(pre[i-1],0ll));
if(i != 1)
{
pii t = query(1,1,n,1,i);
update(t.first + sucf[i] - a[i],i,pre[t.second-1] > 0 ? pre_lab[t.second-1] : t.second);
}
add(1,1,n,1,i,a[i]);
}
}
if(x != y)
{
cout<<ans<<endl;
cout<<x<<" "<<y<<endl;
}
else
{
cout<<ans<<endl;
if(n == 2)
{
cout<<1<<" "<<2<<endl;
return 0;
}
for(int i = 1,cnt = 0;i <= n && cnt != 2;i++)
if(i != x)
{
cout<<i;
if(!cnt) cout<<" ";
else cout<<endl;
cnt++;
}
}
}
/*/
10
-2546 6270 4046 -1443 2914 167 6298 -2386 799 1928
*
30
-2814 -370 990 1452 -920 5855 467 -1733 344 4542 6664 2683 -2923 1295 -3165 -1183 3517 -2978 6225 -983 4390 770 979 5043 5134 2063 -372 -2669 2940 6340
100
6060 5485 -1979 -2685 1642 -3225 1790 -1776 5222 -2005 5206 -2594
2613 4126 -619 1804 3785 5984 6312 5196 -1869 2837 946 5817 -3072 -1478 -1624 4662 -1217
603 6288 2796 -1946 3205 -1052 -164 6470 -1219 -1988 -1214 -1252 5331 -1676 -3172 -2685 5597 2539
6485 139 -1572 -3093 -936 -3038 -1387 4730 2555 -2659 5430 3109 2015 5158 1668 2375 -993 6250 4558
5124 -2389 3701 -2749 3767 5957 2609 483 3318 2665 5767 -1118 -659 1122 -1210 6665 -584 4963 2004 915 1967
-1903 2829 3646 6079 -118 -1183 -1129 -2250 -3233 3327 5123 -1236 5694
/*/