BSUIR Open 2017 Finals Financial Reports(线段树)

185 篇文章 0 订阅
116 篇文章 0 订阅

题意: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 

/*/


### 回答1: 你可以在 CSDN 上创建一个项目,然后将文件上传到该项目中。具体步骤是:登录 CSDN,进入个人中心,点击“我的项目”,然后点击“创建项目”,填写项目信息,选择“上传文件”,将文件上传到项目中即可。如果你遇到了问题,可以在 CSDN 的帮助中心中查找相关的教程或者向客服咨询。 ### 回答2: 要上传文件到“finals hell”,您可以按照以下步骤操作: 1. 首先,打开您的电脑,并连接到互联网。 2. 打开您的网页浏览器,并键入“finalshell.com”。然后按下“Enter”键,访问“finals hell”网站。 3. 如果您还没有账户,请先注册一个新的账户。您需要提供有效的电子邮件地址和创建一个安全的密码。完成填写后,按照账户创建的指引完成注册。 4. 注册完成后,使用您的电子邮件地址和密码登录到“finals hell”账户。 5. 在登录后的页面上,您将找到一个“上传文件”或类似的选项。通常,它会显示为一个按钮或一个图标。 6. 单击“上传文件”选项,这将打开一个文件浏览器对话框。 7. 在文件浏览器对话框中,浏览并选择您要上传的文件。您可以通过双击文件或者选择文件后点击“打开”按钮来选取文件。 8. 一旦您选择了文件,等待上传完成。此过程的时间取决于文件大小和您的互联网连接速度。 9. 上传完成后,您将收到通知或者文件会在页面上显示。您现在可以将该文件与其他人共享或者进行其他相关操作。 10. 完成后,您可以继续上传其他文件或者退出“finals hell”账户。 请注意,以上步骤仅为基本指导。根据具体情况,界面和操作可能会略有不同。对于更详细的指导,请参考“finals hell”网站上的帮助文档或联系他们的客户支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值