[PKUSC2018]神仙的游戏 FFT

版权声明:xgc原创文章,未经允许不得转载。 https://blog.csdn.net/xgc_woker/article/details/82798820

Description
给你一个只有01和?的字符串,问你是否存在一种把?改成01的方案使串存在一个长度为1−n的border。


Sample Input
1?0?


Sample Output
17


被gay队D飞的题。。。
这题肉老大看了一眼说是FFT%%%
式子就会化成: t [ i ] t [ j ] ( A [ i ] B [ j ] ) t[i]*t[j]*(A[i]-B[j])
当这个点为?时,t[i]=0,那么式子得出来就会是0,如果两个数相同,式子得出来也会是0,然后就变成FFT然后判结果是不是0即可。
但有一点就是两个相同的?,可能会有不同的值。。。
然后就%gay。。。
因为你对于长度为k的匹配串,那么第i个位置会跟i+len-k匹配那么其实i+len-k又会跟,i+len-k+len-k匹配,那你就这样跳着判一下即可,时间复杂度可用调和级数证明。


#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
const double PI = acos(-1.0);

struct Complex {
	double r, i;
	Complex() {r = i = 0;}
	Complex(double _r, double _i) {r = _r, i = _i;}
	friend Complex operator + (Complex a, Complex b) {return Complex(a.r + b.r, a.i + b.i);}
	friend Complex operator - (Complex a, Complex b) {return Complex(a.r - b.r, a.i - b.i);}
	friend Complex operator * (Complex a, Complex b) {return Complex(a.r * b.r - a.i * b.i, a.r * b.i + a.i * b.r);}
} A[2100000], B[2100000];
int u1[2100000], u2[2100000], u3[2100000];
int R[2100000], a[510000];
char ss[510000];

void fft(Complex *yy, int len, int o) {
	for(int i = 0; i < len; i++) if(i < R[i]) swap(yy[i], yy[R[i]]);
	for(int i = 1; i < len; i *= 2) {
		Complex wn(cos(PI / i), sin(o * PI / i));
		for(int j = 0; j < len; j += i * 2) {
			Complex w(1, 0);
			for(int k = 0; k < i; k++, w = w * wn) {
				Complex u = yy[j + k];
				Complex v = yy[j + k + i] * w;
				yy[j + k] = u + v;
				yy[j + k + i] = u - v;
			}
		}
	} if(o == -1) for(int i = 0; i < len; i++) yy[i].r /= len;
}

int main() {
	scanf("%s", ss + 1);
	int n = strlen(ss + 1), nn = n;
	for(int i = 1; i <= n; i++) {
		if(ss[i] == '?') a[i] = 0;
		else a[i] = ss[i] - '0' + 1;
	}
	int m = n;
	for(int i = 0; i < n; i++) A[i].r = a[i + 1] * a[i + 1];
	for(int i = n - 1; i >= 0; i--) B[i].r = a[n - i] * a[n - i];
	m *= 2; int l = 0;
	for(n = 1; n <= m; n *= 2) l++;
	for(int i = 0; i < n; i++) R[i] = (R[i >> 1] >> 1) | (i & 1) << (l - 1);
	fft(A, n, 1), fft(B, n, 1);
	for(int i = 0; i < n; i++) A[i] = A[i] * B[i];
	fft(A, n, -1);
	for(int i = 1; i <= n; i++) u1[i] = int(A[i - 1].r + 0.5);
	for(int i = 0; i < n; i++) A[i] = B[i] = Complex(0, 0);
	for(int i = 0; i < nn; i++) A[i].r = a[i + 1] * a[i + 1] * a[i + 1];
	for(int i = nn - 1; i >= 0; i--) B[i].r = a[nn - i];
	fft(A, n, 1), fft(B, n, 1);
	for(int i = 0; i < n; i++) A[i] = A[i] * B[i];
	fft(A, n, -1);
	for(int i = 1; i <= n; i++) u2[i] = int(A[i - 1].r + 0.5);
	for(int i = 0; i < n; i++) A[i] = B[i] = Complex(0, 0);
	for(int i = 0; i < nn; i++) A[i].r = a[i + 1];
	for(int i = nn - 1; i >= 0; i--) B[i].r = a[nn - i] * a[nn - i] * a[nn - i];
	fft(A, n, 1), fft(B, n, 1);
	for(int i = 0; i < n; i++) A[i] = A[i] * B[i];
	fft(A, n, -1);
	for(int i = 1; i <= n; i++) u3[i] = int(A[i - 1].r + 0.5);
	LL ans = 0;
	for(int i = 1; i < nn; i++) {
		LL o = (LL)i * i;
		if(i <= nn / 2) {
			int p = u3[i] + u2[i] - u1[i] * 2;
			if(p == 0) ans ^= o;
		} else {
			int p = u3[i] + u2[i] - u1[i] * 2;
			if(p)continue;
			int k = nn - i; bool bk = 0;
			for(int j = k; j < nn; j += k) {
				int q = nn - j;
				p = u3[q] + u2[q] - u1[q] * 2;
				if(p != 0) bk = 1;
			} if(!bk) ans ^= o;
		}
	} printf("%lld\n", ans ^ ((LL)nn * nn));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xgc_woker/article/details/82798820
FFT