\(\text{Rings}\)

解法

先开始想了一堆杂七杂八的情况,但实际上一个 \(0\) 就够了…

  • 串中没有 \(0\)。直接选 1 n-1 2 n
  • 有在 \(i\in[1,n/2]\) 中的 \(0\)。选 i n i+1 n
  • 有在 \(i\in[n/2+1,n]\) 中的 \(0\)。选 1 i 1 i-1

\(\text{Two Hundred Twenty One}\)

解法

观察样例我们可以发现答案只有 \(0,1,2\)。预处理前缀和 \(pre_i\)。考虑最终序列长度一定是偶数,我们不妨做出以下猜想:

  • \(pre_r-pre_{l-1}=0\)。这个其实也不用猜也知道答案是 \(0\)
  • 长度为偶数。答案是 \(2\)。而且这也是答案最小的情况。
  • 长度为奇数。答案是 \(1\)。而且这也是答案最小的情况。

长度为偶数的序列随便删一个就是奇数的情况,所以我们只用证明长度为奇数答案是 \(1\) 即可。

由于删掉一个数后,它后面的和会取相反数,所以问题转化为能否找到一个数,它左右两边的和相等。

\(s=pre_r-pre_{l-1}\)。如果删掉的数 贡献\(1\),我们希望它左边的和是 \(\frac{s-1}{2}\);如果删掉的数 贡献\(-1\),我们希望它左边的和是 \(\frac{s+1}{2}\)。而这两个数在 \(0\)\(s\) 之间,且一个数只会让序列和变化 \(1\)\(-1\),所以必定是有解的。

如何构造长度为奇数的答案?用 g[0/1][V] 存储贡献为 \(1\)\(-1\),前缀和到这一位是 \(V\) 的所有 \(i\)。对于每个询问在对应的 vector 里二分即可。需要注意实现时这两个数最好用整除,不然可能会出现 \(\mathtt{qqgg}\) 的问题。

代码

#include <cstdio>
#define print(x,y) write(x),putchar(y)

template <class T>
inline T read(const T sample) {
	T x=0; char s; bool f=0;
	while((s=getchar())>'9' or s<'0')
		f|=(s=='-');
	while(s>='0' and s<='9')
		x=(x<<1)+(x<<3)+(s^48),
		s=getchar();
	return f?-x:x;
}

template <class T>
inline void write(const T x) {
	if(x<0) {
		putchar('-'),write(-x);
		return;
	}
	if(x>9) write(x/10);
	putchar(x%10^48);
}

#include <vector>
#include <algorithm>
using namespace std;

const int maxn=3e5;

int n,q,pre[maxn+2];
char s[maxn+3];
vector <int> g[2][(maxn<<1)+5];
vector <int> :: iterator it;

void calc(int x,int y) {
	int s=pre[y]-pre[x-1];
	int r=(s-1>>1)+pre[x-1]+1;
	it=lower_bound(g[0][r+maxn].begin(),g[0][r+maxn].end(),x);
	if(it!=g[0][r+maxn].end() and *it<=y)
		return (void)(print(*it,'\n'));
	r=(s+1>>1)+pre[x-1]-1;
	it=lower_bound(g[1][r+maxn].begin(),g[1][r+maxn].end(),x);
	if(it!=g[1][r+maxn].end() and *it<=y)
		return (void)(print(*it,'\n'));
}

int main() {
	for(int T=read(9);T;--T) {
		n=read(9),q=read(9);
		scanf("%s",s+1);
		for(int i=1;i<=n;++i) {
			pre[i]=pre[i-1]+(s[i]=='+'?1:-1)*((i&1)?1:-1);
			if((s[i]=='+' and (i&1)) or (s[i]=='-' and !(i&1)))
				g[0][pre[i]+maxn].push_back(i);
			else g[1][pre[i]+maxn].push_back(i);
		}
		while(q--) {
			int x,y;
			x=read(9),y=read(9);
			if(pre[y]-pre[x-1]==0)
				puts("0");
			else if((y-x)&1) {
				puts("2");
				print(x,' ');
				calc(x+1,y);
			}
			else {
				puts("1");
				calc(x,y);
			}
		}
		for(int i=1;i<=n;++i)
			if((s[i]=='+' and (i&1)) or (s[i]=='-' and !(i&1)))
				g[0][pre[i]+maxn].clear();
			else g[1][pre[i]+maxn].clear();
	}
	return 0;
}
posted on 2021-09-01 12:24  Oxide  阅读(29)  评论(0编辑  收藏  举报