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

浙公网安备 33010602011771号