最近連續被構造題坑,希望能借這些題好好總結(區間統一修改,差分是永恆的主題!!)
考慮每個數至少需要多少次操作,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;
}