C2 - Pokémon Army (hard version)(思维+差分/线段树+dp)详解

https://codeforces.com/contest/1420/problem/C2


这道题十分的锻炼思维,也让我知道了同样是差分,从前面减后面和从后面减前面是有不同的意义的。

还记得c1吗?我们是找波峰波谷的,实际上这个波峰波谷如果用差分的想法去找,可以做出c2的题。什么意思?

波峰波谷的差值一定是中间值之差的和,那么波峰波谷就是看成了能不能做差做下去。

比如1 2 5 4 3 6 7,从前往后差分是 -1,-3,1,2,-3,-1,7.会发现这样一个事情。把正数的差分全部加上去,就是最后求出的波峰波谷的最终值。

比如5 4 3找的是5 3(在上面的例子中)找出来的差值其实就是(5 - 4) + (4 - 3)

找到的那个最小值,一定波峰和波谷的值程单调性,那这两个值之间所有数的两两之差就是答案

如果画一个模拟的图5-4-3直线可以发现中间的点差不多没有影响,其实也就是这些值之间的两两之差。

那么发现了这个之后,后面的操作就是相当于把这个数组里的两个数字位置改变一下,重新进行这样类似的操作。

交换前考虑一下l的前后是不是正数,如果是就减掉,r的前后是不是正数,如果是就减掉。注意l==r-1的情况特判,防止多加多减。包含在里面一个情况就好了。

交换后看是否有相邻差为正的,正的就加上去。然后输出。swap就好了。

启发:找波峰波谷可以前往后差分去思考。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=3e5+100;
typedef long long LL;
LL a[maxn];
void solve()
{
	LL n,q;cin>>n>>q;
	LL res=0;
	for(LL i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(LL i=1;i<=n;i++){
		if(a[i]-a[i+1]>0) res+=(a[i]-a[i+1]);
	}
	cout<<res<<endl;
	while(q--)
	{
		LL l,r;cin>>l>>r;
		if(a[l-1]-a[l]>0) res-=(a[l-1]-a[l]);
		if(a[r-1]-a[r]>0&&l!=r-1) res-=(a[r-1]-a[r]);
		if(a[l]-a[l+1]>0) res-=(a[l]-a[l+1]);
		if(a[r]-a[r+1]>0) res-=(a[r]-a[r+1]);
		
		swap(a[l],a[r]);
		if(a[l-1]-a[l]>0) res+=(a[l-1]-a[l]);
		if(a[r-1]-a[r]>0&&l!=r-1) res+=(a[r-1]-a[r]);
		if(a[l]-a[l+1]>0) res+=(a[l]-a[l+1]);
		if(a[r]-a[r+1]>0) res+=(a[r]-a[r+1]);
		cout<<res<<endl;
	}
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL t;cin>>t;
  while(t--)
  {
  	memset(a,0,sizeof(a)); 
  	solve();
  }
return 0; 
}
 

最后补充一下线段树的dp。这个我是看别人提交的。但是我看不懂这个转移。

这个常数挺大的//写得丑了会TLE。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
#define INF 1e18;
using namespace std;
const int maxn=3e5+100;
typedef long long LL;
int n,q;
int a[maxn];
struct Node{
	LL v[2][2];
	Node(){
		v[0][0]=v[1][1]=v[0][1]=v[1][0]=-INF;
	}
	Node(LL x){
		v[0][0]=x;
		v[1][1]=-x;
		v[0][1]=v[1][0]=-INF;
	}
	Node operator+(Node &p){
		Node ret;
		for(int i=0;i<2;i++){
			for(int j=0;j<2;j++)
			{
				ret.v[i][j]=max({v[i][j],p.v[i][j],v[i][0]+p.v[1][j],v[i][1]+p.v[0][j]});
			}
		}
		return ret;
	}
}tree[maxn*4];
void update(int p,int l,int r,int i,int x)
{
	if(l==r){
		tree[p]=Node(x);return;
	}
	int mid=(l+r)>>1;
	if(i<=mid) update(p*2,l,mid,i,x);
	if(i>mid) update(p*2+1,mid+1,r,i,x);
	tree[p]=tree[p*2]+tree[p*2+1];
}
int main(void)
{
  //cin.tie(0);std::ios::sync_with_stdio(false);
  int t;scanf("%d",&t);
  while(t--)
  {
  	scanf("%d%d",&n,&q);
  //	for(LL i=0;i<=n+10;i++) a[i]=0,update(1,1,n,i,a[i]); 
	for(int i=1;i<=n;i++) cin>>a[i],update(1,1,n,i,a[i]);
  	printf("%lld\n",tree[1].v[0][0]);
  	while(q--)
  	{
  		int l,r;scanf("%d%d",&l,&r);
  		swap(a[l],a[r]);
  		update(1,1,n,l,a[l]);
  		update(1,1,n,r,a[r]);
  		printf("%lld\n",tree[1].v[0][0]);
  	}
  }
return 0;
}
 

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/108819446