传送门
文章目录
- 题意:
- 思路:
题意:
给你一个长度为nnn的串,+++代表111,−-−代表−1-1−1,让后有qqq个询问,每次询问[l,r][l,r][l,r]区间,将这段区间的数拿出来,设为a[1,r−l+1]a[1,r-l+1]a[1,r−l+1],算a1−a2+a3−...=xa_1-a_2+a_3-...=xa1−a2+a3−...=x,问最少删去多少个数才能使得xxx为000,输出删的数的位置。
n,q≤3e5n,q\le3e5n,q≤3e5
思路:
首先考虑简单版本,就是不要求输出删的位置,只考虑删多少。
每次询问拿出来的区间,奇偶位置符号分别乘1,−11,-11,−1,不难发现我们将−1,1-1,1−1,1倒过来也是没有影响的,也就是偶奇分别乘1,−11,-11,−1。
那么既然拿出来的区间对位置奇偶没影响,那么我们考虑一开始就处理一个a[i]a[i]a[i]表示第iii个位置的数,再维护个前缀和sum[i]sum[i]sum[i],我们现在能得到[l,r][l,r][l,r]的和了,考虑如何计算答案。
(1)(1)(1)如果当前区间和是000,那么答案显然为000。
(2)(2)(2)如果当前区间和为奇数,那么一定可以找到一个位置,去掉当前位置后区间和为000。
(3)(3)(3)如果当前区间和为偶数,那么我们可以把lll的位置删掉,这样区间和一定变为奇数,让后再按照(2)(2)(2)来找一个位置去掉即可。
所以如果是easyeasyeasy版本的话,分以上三种讨论即可。
考虑如果要求输出位置怎么办。
对于(1)(1)(1),直接输出000即可。
对于(2)(2)(2),由于其一定存在一个位置去掉后区间和为000,考虑什么位置去掉是合法的呢?假设我们去掉的位置是pospospos,那么[l,pos−1],[pos+1,r][l,pos-1],[pos+1,r][l,pos−1],[pos+1,r]两个区间的和原本是相同的,也就是sum[l,pos−1]=sum[pos+1,r]sum_{[l,pos-1]}=sum_{[pos+1,r]}sum[l,pos−1]=sum[pos+1,r],那么我们去掉pospospos位之后,前面的不变,后面的值全部取反,也就是sum[l,pos−1]=−sum[pos+1,r]sum_{[l,pos-1]}=-sum_{[pos+1,r]}sum[l,pos−1]=−sum[pos+1,r],也就是说我们找到这样的一个合法位置即可。
考虑怎么找呢?显然可以二分来找,二分位置,有点小繁琐,我们考虑一种更加妙的方式。
我们给每个sum[i]+sum[i−1]sum[i]+sum[i-1]sum[i]+sum[i−1]开一个桶,存下来iii这个位置,考虑当前询问区间为[l,r][l,r][l,r]。你那么我们找到sum[l−1]+sum[r]sum[l-1]+sum[r]sum[l−1]+sum[r]对应的桶里的某个位置xxx,那么现在有sum[r]+sum[l−1]=sum[x]+sum[x−1]sum[r]+sum[l-1]=sum[x]+sum[x-1]sum[r]+sum[l−1]=sum[x]+sum[x−1],移项得sum[r]−sum[x]=sum[x−1]−sum[l−1]sum[r]-sum[x]=sum[x-1]-sum[l-1]sum[r]−sum[x]=sum[x−1]−sum[l−1],不难发现,如果我们将xxx这个位置去掉后,那么前后两个区间的和就为000了,所以我们只需要在sum[i]+sum[i−1]sum[i]+sum[i-1]sum[i]+sum[i−1]的桶内二分一个位置即可,由于保证一定有解,所以一定存在这样的一个位置。
对于(3)(3)(3),删掉lll位置,将其变为奇数,让后进行(2)(2)(2)即可。
// Problem: D1. Two Hundred Twenty One (easy version)
// Contest: Codeforces - Codeforces Round #741 (Div. 2)
// URL: https://codeforces.com/contest/1562/problem/D1
// Memory Limit: 512 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;const int N=2000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;int n,q;
int a[N],sum[N];
vector<int>v[N];
char s[N];int get(int l,int r) {int now=sum[l]+sum[r]+2*n;int pos=lower_bound(v[now].begin(),v[now].end(),l+1)-v[now].begin();return v[now][pos];
}int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);int _; scanf("%d",&_);while(_--) {scanf("%d%d%s",&n,&q,s+1);for(int i=1;i<=n;i++) {if(s[i]=='-') {if(i%2==1) sum[i]=sum[i-1]-1;else sum[i]=sum[i-1]+1;}else {if(i%2==1) sum[i]=sum[i-1]+1;else sum[i]=sum[i-1]-1;}}for(int i=1;i<=n;i++) v[sum[i]+sum[i-1]+2*n].pb(i);while(q--) {int l,r; scanf("%d%d",&l,&r);int now=abs(sum[r]-sum[l-1]);if(now==0) puts("0");else if((r-l+1)%2==1) { puts("1");printf("%d\n",get(l-1,r));} else {puts("2");printf("%d %d\n",l,get(l,r));}}for(int i=1;i<=n;i++) v[sum[i]+sum[i-1]+2*n].clear();}return 0;
}
/*
1
14 3
+--++---+++---
1 14
6 12 ---+++- -1 1 -1 -1 1 -1 -1
3 102
1 5
1
12
0*/