「PKUSC2018」神仙的游戏(border性质+NTT)

https://loj.ac/problem/6436

记得一年多前hzj讲这题时不太会的,现在已经能很容易切掉了。

考虑border的性质,若有一个长度为\(i\)的border,则\(\forall x\in[1,i],s[x]=s[x+(n-i)]\)

\(g[i]=f[n-i]\)

那么,若有\(s[i]=0,s[j]=1或s[i]=1,s[j]=0(i<j)\),则\(\forall d|j-i,g[d]=0\)

先用NTT求出有哪些\(j-i\)满足\(s[i]=0,s[j]=1或s[i]=1,s[j]=0(i<j)\)

\(O(n~log~n)\)枚举每个数的倍数得到\(g[d]\),就没了

Code:


#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int mo = 998244353;

ll ksm(ll x, ll y) {
	ll s = 1;
	for(; y; y /= 2, x = x * x % mo)
		if(y & 1) s = s * x % mo;
	return s;
}

#define V vector<ll>
#define si size()
#define re resize

const int nm = 1048576;
namespace ntt {
	int r[nm]; ll w[nm];
	void build() {
		for(int i = 1; i < nm; i *= 2) {
			w[i] = 1; ll v = ksm(3, (mo - 1) / 2 / i);
			ff(j, 1, i) w[i + j] = w[i + j - 1] * v % mo;
		}
	}
	void dft(ll *a, int n, int f) {
		ff(i, 0, n) {
			r[i] = r[i / 2] / 2 + (i & 1) * (n / 2);
			if(i < r[i]) swap(a[i], a[r[i]]);
		} ll b;
		for(int i = 1; i < n; i *= 2) for(int j = 0; j < n; j += 2 * i) ff(k, 0, i)
			b = a[i + j + k] * w[i + k], a[i + j + k] = (a[j + k] - b) % mo, a[j + k] = (a[j + k] + b) % mo;
		if(f == -1) {
			reverse(a + 1, a + n);
			b = ksm(n, mo - 2);
			ff(i, 0, n) a[i] = (a[i] + mo) * b % mo;
		}
	}
}
using ntt :: dft;

const int N = 5e5 + 5;

char s[N]; int n, n0;

int f[N];

ll a0[nm], a1[nm];
ll b0[nm], b1[nm];
ll d[nm];

int main() {
	ntt :: build();
	scanf("%s", s + 1);
	n = strlen(s + 1);
	n0 = 1; while(n0 <= 2 * n) n0 *= 2;
	fo(i, 1, n) if(s[i] == '0')
		a0[n - i] = a1[i] = 1;
	fo(i, 1, n) if(s[i] == '1')
		b0[n - i] = b1[i] = 1;
	dft(a0, n0, 1); dft(a1, n0, 1);
	dft(b0, n0, 1); dft(b1, n0, 1);
	ff(i, 0, n0) {
		d[i] = (a0[i] * b1[i] + a1[i] * b0[i]) % mo;
	}
	dft(d, n0, -1);
	fo(i, 1, n) f[i] = d[n + i];
	fo(i, 1, n) fo(j, 1, n / i) f[i] |= f[i * j];
	ll ans = 0;
	fo(i, 1, n) if(!f[n - i]) ans ^= (ll) i * i;
	pp("%lld\n", ans);
}
posted @ 2020-04-02 21:06  Cold_Chair  阅读(239)  评论(0编辑  收藏  举报