CF1562 D2. Two Hundred Twenty One (hard version)(思维)

目录

Description

有一个包含 \(+-\) 的字符串,其中 \(+\) 表示 \(1\)\(-\) 表示 \(-1\), 给出 \(m\) 个区间,求删掉最少的字符,区间和为零,其中 \(a[i]=(-1)^{i-1}*a[i]\),输出删除字符的位置

State

\(1<=n,q<=3*10^5\)

\(1<=t<=10^3\)

\(1<=l<=r<=n\)

Input

3
14 1
+--++---++-++-
1 14
14 3
+--++---+++---
1 14
6 12
3 10
4 10
+-+-
1 1
1 2
1 3
1 4
2 2
2 3
2 4
3 3
3 4
4 4

Output

2
5 8
2
1 11
1
9
0
1
1
2
1 2
1
2
2
1 3
1
2
2
2 3
1
3
1
3
2
3 4
1
4

Solution

如果删除一个位置 \(p\),假设原来的区间和为 \(sum\),那么该区间为 \(0\),就需要满足 \(sum-a[p]-2*res=0\),其中 \(res\) 为原来区间 \([p+1,r]\) 的区间和;

该式子可以变为 \(sum[r]-sum[l - 1]-a[p]=2*(sum[r]-sum[p])\),剩下只有 \(a[p]\) 很显眼,

\[sum[r]-sum[l-1]-sum[p]+sum[p-1]=2*(sum[r]-sum[p]) \]

最后化简为:

\[sum[r]+sum[l-1]=sum[p-1]+sum[p] \]


Code

const int N = 3e5 + 5;

    int n, m, _, k;
    int a[N];
    int sum[N];
    map<int, set<int>> all;

int go(int l, int r)
{
    int res = sum[r] + sum[l - 1];
    return *all[res].lower_bound(l);
}

signed main()
{
    //IOS;
    string s;
    rush(){
        cin >> n >> m;
        cin >> s;
        for(int i = 0; s[i]; i ++){
            int id = 1;
            if(i & 1) id *= -1;
            if(s[i] == '-') id *= -1;
            a[i + 1] = id;
        }
        all.clear();
        for(int i = 1; i <= n; i ++){
            sum[i] = sum[i - 1] + a[i];
            all[sum[i] + sum[i - 1]].insert(i);
        }
        while(m --> 0){
            int l, r;
            cin >> l >> r;
            int res = sum[r] - sum[l - 1];
            if(res == 0){
                printf("0\n");
            }
            else if(res & 1){
                printf("1\n%d\n", go(l, r));
            }
            else{
                printf("2\n%d %d\n", r, go(l, r - 1));
            }
        }
    }
    //PAUSE;
    return 0;
}
posted @ 2021-09-23 08:09  Bcoi  阅读(75)  评论(0)    收藏  举报