[CC-SEINC]Sereja and Subsegment Increasings

[CC-SEINC]Sereja and Subsegment Increasings

题目大意:

有长度为\(n(n\le10^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\),答案即为\(\sum\max(D_i,0)\)

而模\(4\)相当于可以对\(C\)区间加\(4\),对应到\(D\)上就是对于区间\((l,r]\)\(D_l+=4,D_r-=4\)

考虑怎样选择区间能够使答案更优。

对于区间\((l,r]\),考虑以下情况:

  1. \(D_l=2,D_r=-3\),会使答案\(-1\)
  2. \(D_l=3,D_r=-2\),会使答案\(-1\)
  3. \(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\n",ans);
	}
	return 0;
}
posted @ 2018-08-18 13:46  skylee03  阅读(127)  评论(0编辑  收藏  举报