[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;
}

猜你喜欢

转载自www.cnblogs.com/skylee03/p/9497126.html
cc