「PKUSC2018」神仙的游戏(border性质+NTT)
记得一年多前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);
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址