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()); }