1. 程式人生 > >[CC-SEINC]Sereja and Subsegment Increasings

[CC-SEINC]Sereja and Subsegment Increasings

執行 多少 -i 相等 int() etc line 序列 segment

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

[CC-SEINC]Sereja and Subsegment Increasings