最近连续被构造题坑,希望能借这些题好好总结(区间统一修改,差分是永恒的主题!!)
考虑每个数至少需要多少次操作,c1[i]=(b[i]-a[i]+4)%4,当然,如果进行c[i]=c1[i]+4*e次操作也能符合条件;
假设我们已经知道了要每个钟要操作多少次,那么要通过多少次区间操作完成?
差分,值为
这个可以画张图考虑,把每个值看做坐标轴上的长方形,每次只能取一个区间高度为1的长方形
若左边长方形高度<右边长方形高度,只要在取右边长方形时顺便取一下即可(不用加次数)
若左边长方形高度>右边长方形高度,高的长度肯定要单独取
因此我们只要找到一种方案 c[i]使其zhi=最小即可
先不考虑给c[i]加上4,答案就是zhi=。
考虑 k[i]=c[i]-c[i-1]
现在考虑如果对(l,r]加上4,那么有影响的只有kl和kr,
k[l]-4,k[r]+4。
如果k[l]=0那么不用考虑,因为答案不可能变小,(因为最初时这两个点对值的贡献为0+k[r],现在为0+k[r]+4,不减反增)
如果k[l]=1,也不用考虑。(因为最初时这两个点对值的贡献为1+k[r],现在为0+k[r]+4,不减反增)
如果k[l]=2,当k[r]=-3,答案会变小1(因为最初时这两个点对值的贡献为2+0,现在为0+1)
如果k[l]=3,当k[r]=-3,答案会变小2,(因为最初时这两个点对值的贡献为3+0,现在为0+1) (因为这个贡献大于下一个,所以在匹配 时先要考虑这个)
当k[r]=-2时,答案会变小1(因为最初时这两个点对值的贡献为3+0,现在为0+1)
所以我们只要从1~n不断地把-3跟2或3匹配,-2跟3匹配即可。
如何匹配(这里条件比较简单,用小技巧解决),比较复杂时用dp
#include<bits/stdc++.h>
using namespace std;
long long n,d2,d3,tot,zhi,a[2000000],b[2000000];
inline int read(){
int out=0,flag=1;char c=getchar();
while(c<48||c>57) {if(c=='-') flag=-1;c=getchar();}
while(c>=48&&c<=57){out=out*10+c-48;c=getchar();}
return out*flag;
}
int main()
{ n=read();
for (int i=1;i<=n;i++)
a[i]=read();
for (int i=1;i<=n;i++)
{
b[i]=read();
a[i]=(b[i]-a[i]+4)%4;
}
//for (int i=1;i<=n;i++)
//cout<<a[i]<<' '; cout<<endl;
for (int i=1;i<=n;i++) a[i]=a[i]-a[i+1];
//for (int i=1;i<=n;i++)
//cout<<a[i]<<' ';
//cout<<endl;
for (int i=1;i<=n;i++)
{ if (a[i]>0) tot+=a[i];
if (a[i]==2) d2++;
if (a[i]==3) d3++;
if (a[i]==-3) { if (d3>0) {d3--;tot=tot-2;}
else if (d2>0) {d2--; tot=tot-1;}
}
if (a[i]==-2) { if (d3>0) {d3--;tot=tot-1;d2++;}} //匹配小技巧:如果之后有-3以匹配-2,相当于还能再减1
}
cout<<tot<<endl;
}