链接
题意:
给出长度为n的字符串,
(
+
,
1
)
(
−
,
−
1
)
(+,1)(-,-1)
(+,1)(−,−1),然后k次询问,查询区间
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri],最少去除多少个数使得
a
l
−
a
l
+
1
+
a
l
+
2
−
.
.
.
.
a
r
a_l-a_{l+1}+a_{l+2}-....a_{r}
al−al+1+al+2−....ar也就是
∑
i
=
l
r
(
−
1
)
(
i
−
l
)
\sum _{i=l}^{r}(-1)^(i-l)
∑i=lr(−1)(i−l);
分析:
首先我们看D1是让我求出最少去除多少个数,
- 如果区间内已经成0了, 那么一定输出0,
- 如果区间值为奇数,那么一定可以通过减去区间内一个使满足条件,a为+1数量,b为-1数量,那么(a-b)一定是奇数我假设a>b,那么我们需要减去一个数,假设减去+1,那么会变成(a-1,b)所以我们想减去这个数位置为i, ( i , r ] (i,r] (i,r]中间+1数量比-1数量多(a-1-b)/2个。这样我们就能使 +1和-1数量相等。
- 如果区间值为偶数,那么一定可以通过减去两个数使得满足条件,减去一个相当于从 i − r i-r i−r,减两个相当于 ( i − j ) (i-j) (i−j),性质是一样的。
我们知道去除几个数后,需要看看去除那个位置,那么我们按照上面的思考,
收我们我们用数存储,这样使得我们知道每个位置的值,然后我们需要二分查找位置,使得满足条件。
ll n,m;
string str;
void check(ll l,ll r){
ll cha =v[r]-v[l-1];
ll x=l-1;
ll y=r;
while(y-x>1){
ll mid=(x+y)/2;
if(abs(v[mid]-v[l-1]) < abs(v[mid]-v[r])){
x=mid;
}
else {
y=mid;
}
}
printf("%lld\n",y);
}
void solve()
{
v.clear();
cin>>n>>m;
cin>>str;
str=" "+str;
ll sum=0;
v.push_back(0);
for(int i=1;i<=n;i++){
if(i%2){
if(str[i]=='+') sum++;
else sum--;
}else{
if(str[i]=='+') sum--;
else sum++;
}
v.push_back(sum);
}
while(m--){
ll l,r;
cin>>l>>r;
ll cha=v[r]-v[l-1];
if(cha==0){puts("0");}
else if(cha%2){
puts("1");
check(l,r);
}else {
puts("2");
printf("%lld ",l);
check(++l,r);
}
}
}