Codeforces 1037G:A Game on Strings(SG函数)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/82747316

传送门

题解:

直接暴力SG函数求解即可。 可以证明有用区间只有 O ( 26 n ) O(26 n) 个。

#include <bits/stdc++.h>
using namespace std;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=1e5+50;
char ch[N];
int n,a[N],pre[N][26],suf[N][26];
int f[N][26],g[N],mem[27];

inline int mex(int sta) {return __builtin_ctz(~sta);}
inline int calc(int l,int r,int c,int flag) {
	if(l>r) return 0;
	if(~mem[c]) return mem[c];
	
	int sta=0;
	for(int j=0;j<26;++j) {
		int _l=suf[l][j], _r=pre[r][j];
		if(_r>=l) sta|=1<<(g[_r]^g[_l]^(!flag ? f[_l-1][c] : calc(l,_l-1,j,1))^(flag ? f[r][j] : calc(_r+1,r,j,0)));
	}
	return mem[c]=mex(sta);
}

int main() {
	scanf("%s",ch+1); n=strlen(ch+1);
	for(int i=1;i<=n;i++) a[i]=ch[i]-'a';
	for(int i=1;i<=n;i++) {
		for(int j=0;j<26;++j) pre[i][j]=pre[i-1][j];
		pre[i][a[i]]=i;
	}
	for(int j=0;j<26;++j) suf[n+1][j]=n+1;
	for(int i=n;i>=1;i--) {
		for(int j=0;j<26;++j) suf[i][j]=suf[i+1][j];
		suf[i][a[i]]=i;
	}
	for(int i=1;i<=n;i++) {
		g[i]=f[i-1][a[i]]^g[pre[i-1][a[i]]];
		memset(mem,-1,sizeof(mem));
		for(int j=0;j<26;++j) f[i][j]=calc(pre[i][j]+1,i,j,0);
	}
	
	int q=rd();
	for(int i=1;i<=q;i++) {
		int l=rd(), r=rd();
		memset(mem,-1,sizeof(mem));
		if(calc(l,r,26,1)) puts("Alice");
		else puts("Bob");
	}
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/82747316