[CC-SEINC]Sereja and Subsegment Increasings

[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]),考虑以下情况:

  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
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/skylee03/p/9497126.html