Jzoj4788 序列

题意:给你a,b两个序列,每次可以在区间[l,r]对每个数加一,求最少的步数使a变成b

注意,整个过程都是在mod 4的意义下的,a,b所有元素的值都在[0,3]之间

我们可以先考虑不存在Mod 4 的情况

我们假设di=max(0,bi-ai)

那么显然,对于一个位置i,我们需要将其操作max(0,di)次

考虑从1开始,我们设f[i]表示将1~i的d清零所需要的最小次数

显然,f[1]=d[1],f[i]=f[i-1]+max(0,d[i]-d[i-1]) (其实这是一个差分的经典应用)

现在我们来考虑Mod 4 的情况,由于有Mod 4 的影响,我们可以将一系列的d[i]变为d[i]+4k

这样在一种情况下会减小答案

若有i<j使得 d[i]-d[i-1]+4<d[j]-d[j-1] 那么,我们就可以将整个[i,j-1]的d都加上4

这样答案就可以减少(d[i]-d[i-1]-dj+dj-1+4)

实际上,我们只需要维护d[i]-d[i-1]=-2和-3的个数即可(-1+4=3 0+4=4显然都不可能)

每次都贪心地去取就可以

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,a[1000010],T;
int aim(){
	scanf("%d",&n); int cnt[4]={0},ans=0;
	for(int i=1;i<=n;++i) scanf("%d",a+i);
	for(int x,i=1;i<=n;++i){
		scanf("%d",&x);
		a[i]=(x-a[i]+4)&3;
	}
	for(int i=1;i<=n;++i) ans+=max(0,a[i]-a[i-1]);
	for(int i=2;i<=n;++i){
		int j=a[i]-a[i-1];
		if(j>0){
			if(cnt[1] && j>1){
				--cnt[1];
				++cnt[j];
				ans-=--j;
			} else if(cnt[2] && j>2){
				--cnt[2];
				++cnt[j];
				ans-=j-2;
			}
		} else ++cnt[j+4];
	}
	printf("%d\n",ans);
}
int main(){ for(scanf("%d",&T);T--;aim()); }

posted @ 2017-10-26 19:54  扩展的灰(Extended_Ash)  阅读(104)  评论(0编辑  收藏  举报