[CC-SEINC]Sereja and Subsegment Increasings
题目大意:
有长度为(n(nle10^5))的序列(A)和(B)。
在一次操作中,可以选择一个区间增加(1)。
求让(A)和(B)在模(4)意义下相等,至少要对(A)执行多少次操作。
思路:
对(A,B)对应作差,(C_i=B_i-A_i)。
求(C)的查分(D_i=C_i-C_{i+1})。
如果不考虑模(4),答案即为(summax(D_i,0))。
而模(4)相当于可以对(C)区间加(4),对应到(D)上就是对于区间((l,r]),(D_l+=4,D_r-=4)。
考虑怎样选择区间能够使答案更优。
对于区间((l,r]),考虑以下情况:
- (D_l=2,D_r=-3),会使答案(-1);
- (D_l=3,D_r=-2),会使答案(-1);
- (D_l=3,D_r=-3),会使答案(-2)。
而其余情况都不会使答案更优。
因此可以线性扫一遍,记录(2,3)出现的次数,将当前点作为右端点时择优更新答案即可。
时间复杂度(mathcal O(n))。
源代码:
#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=1e5+1;
int a[N];
int main() {
for(register int T=getint();T;T--) {
const int n=getint();
for(register int i=1;i<=n;i++) a[i]=getint();
for(register int i=1;i<=n;i++) {
a[i]=(getint()-a[i]+4)%4;
}
int ans=a[n],cnt2=0,cnt3=0;
for(register int i=1;i<n;i++) {
a[i]-=a[i+1];
ans+=std::max(0,a[i]);
}
for(register int i=1;i<=n;i++) {
if(a[i]==2) cnt2++;
if(a[i]==3) cnt3++;
if(a[i]==-2) {
if(cnt3) {
cnt2++;
cnt3--;
ans--;
}
}
if(a[i]==-3) {
if(cnt3) {
cnt3--;
ans-=2;
} else if(cnt2) {
cnt2--;
ans--;
}
}
}
printf("%d
",ans);
}
return 0;
}