FFT与多项式、生成函数题目泛做

时间:2024-01-06 08:36:08

题目1 COGS 很强的乘法问题

高精度乘法用FFT加速

 #include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#define Pi acos(-1) using namespace std;
const int N = + ;
const int rad = ; struct Complex {
double r, i;
Complex(double x = , double y = ) { r = x; i = y; }
Complex operator + (Complex x) { return Complex(r + x.r, i + x.i); }
Complex operator - (Complex x) { return Complex(r - x.r, i - x.i); }
Complex operator * (Complex x) { return Complex(r * x. r - i * x.i, r * x.i + i * x.r); }
}a[N], b[N];; int n, m, l, r[N], c[N];
char ss[N]; void dft(Complex *s, int f) {
for(int i = ; i < n; ++ i)
if(i < r[i]) swap(s[i], s[r[i]]);
for(int i = ; i < n; i <<= ) {
Complex wn(cos(Pi / i), f * sin(Pi / i));
for(int j = ; j < n; j += (i << )) {
Complex w(, );
for(int k = ; k < i; ++ k) {
Complex x = s[j + k], y = w * s[j + k + i];
s[j + k] = x + y;
s[j + k + i] = x - y;
w = w * wn;
}
}
}
if(f == -)
for(int i = ; i < n; ++ i)
s[i].r /= n;
} int main() {
#ifndef stone
freopen("bettermul.in", "r", stdin);
freopen("bettermul.out", "w", stdout);
#endif int len1, len2;
scanf("%s", ss); len1 = strlen(ss);
for(int i = ; i < len1; ++ i) a[i] = ss[len1 - i - ] - '';
scanf("%s", ss); len2 = strlen(ss);
for(int i = ; i < len2; ++ i) b[i] = ss[len2 - i - ] - '';
n = max(len1, len2); m = (n << ) - ;
for(n = ; n <= m; n <<= ) l ++;
for(int i = ; i < n; ++ i)
r[i] = (r[i >> ] >> ) | ((i & ) << (l - ));
dft(a, ); dft(b, );
for(int i = ; i < n; ++ i) a[i] = a[i] * b[i];
dft(a, -);
for(int i = ; i <= m; ++ i) c[i] = (int) (a[i].r + 0.5);
for(int i = ; i <= m; ++ i) {
if(c[i] >= rad) {
c[i + ] += c[i] / rad;
c[i] %= rad;
if(i == m) m ++;
}
}
int pos = m;
while(c[pos] == ) -- pos;
for(int i = pos; i >= ; -- i) printf("%d", c[i]); #ifndef stone
fclose(stdin); fclose(stdout);
#endif
return ;
}

COGS

题目2 BZOJ4259 残缺的字符串

算法讨论:(摘自Claris的博客,写得很清楚,我就是看这个才会做的)

FFT与多项式、生成函数题目泛做

注意:如果开第二个字符串的倍长的话,FFT会超时。还要注意统计答案的区间是什么。不要错了。

 #include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath> using namespace std;
typedef long long ll;
const int N = + ;
#define Pi acos(-1) struct Cp {
double r, i;
Cp(double _r = , double _i = ):
r(_r), i(_i) {}
Cp operator + (Cp x) {
return Cp(r + x.r, i + x.i);
}
Cp operator - (Cp x) {
return Cp(r - x.r, i - x.i);
}
Cp operator * (Cp x) {
return Cp(r * x.r - i * x.i, r * x.i + i * x.r);
}
}; char str1[N], str2[N];
int len1, len2, n, m, l, cnt;
int t[N], ans[N], r[N];
Cp a[N], b[N], A[N], B[N], C[N], tp; void DFT(Cp *s, int f) {
for(int i = ; i < n; ++ i)
if(i < r[i]) swap(s[i], s[r[i]]);
for(int i = ; i < n; i <<= ) {
Cp wn(cos(Pi / i), f * sin(Pi / i));
for(int j = ; j < n; j += (i << )) {
Cp w(, );
for(int k = ; k < i; ++ k) {
Cp x = s[j + k], y = w * s[j + k + i];
s[j + k] = x + y;
s[j + k + i] = x - y;
w = w * wn;
}
}
}
if(f == -)
for(int i = ; i < n; ++ i)
s[i].r /= n;
} #define stone int main() {
#ifndef stone freopen("bitch.in", "r", stdin);
freopen("bitch.out", "w", stdout); #endif scanf("%d%d", &len1, &len2);
scanf("%s%s", str1, str2);
reverse(str1, str1 + len1);
for(int i = ; i < len1; ++ i) {
if(str1[i] == '*') a[i].r = ;
else a[i].r = (str1[i] - 'a' + );
}
for(int i = ; i < len2; ++ i) {
if(str2[i] == '*') b[i].r = ;
else b[i].r = (str2[i] - 'a' + );
}
m = len1 + len2;
for(n = ; n <= m; n <<= ) ++ l;
for(int i = ; i < n; ++ i) r[i] = (r[i >> ] >> ) | ((i & ) << (l - )); for(int i = ; i < n; ++ i) {
A[i].r = a[i].r * a[i].r * a[i].r;
B[i].r = b[i].r;
}
DFT(A, ); DFT(B, );
for(int i = ; i < n; ++ i) { C[i] = C[i] + A[i] * B[i]; }
memset(A, , sizeof A); memset(B, , sizeof B);
for(int i = ; i < n; ++ i) {
A[i].r = a[i].r * a[i].r;
B[i].r = b[i].r * b[i].r;
}
DFT(A, ); DFT(B, ); tp = (Cp) {, };
for(int i = ; i < n; ++ i) { C[i] = C[i] - A[i] * B[i] * tp; }
memset(A, , sizeof A); memset(B, , sizeof B);
for(int i = ; i < n; ++ i) {
A[i].r = a[i].r;
B[i].r = b[i].r * b[i].r * b[i].r;
}
DFT(A, ); DFT(B, );
for(int i = ; i < n; ++ i) { C[i] = C[i] + A[i] * B[i]; }
DFT(C, -);
for(int i = len1 - ; i < len2; ++ i)
if(C[i].r < 0.5) {
ans[++ cnt] = i - len1 + ;
}
printf("%d\n", cnt);
for(int i = ; i <= cnt; ++ i) {
printf("%d ", ans[i]);
} #ifndef stone fclose(stdin); fclose(stdout); #endif return ;
}

4259

题目3 BZOJ 万径人踪灭

算法讨论:

用FFT算出所有回文串(相邻的和不相邻的),然后用Manacher计算出所有相邻的回文串,然后做差统计答案即可。

用FFT算出所有回文串的时候,是有len + len - 1个位置要计算的,分别是在字符的位置上和在两个字符之间的位置。

 #include <cstdlib>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath> using namespace std;
const int N = + ;
typedef long long ll;
const int mod = 1e9 + ;
#define Pi acos(-1) struct Cp {
double r, i;
Cp(double _r = , double _i = ) :
r(_r), i(_i){}
Cp operator + (Cp x) {
return Cp(r + x.r, i + x.i);
}
Cp operator - (Cp x) {
return Cp(r - x.r, i - x.i);
}
Cp operator * (Cp x) {
return Cp(r * x.r - i * x.i, r * x.i + i * x.r);
}
}; char ss[N], Ma[N << ];
int n, m, l, r[N], lens;
Cp a[N], b[N];
ll Mp[N << ], t1[N], t2[N], p[N]; void DFT(Cp *s, int f) {
for(int i = ; i < n; ++ i)
if(i < r[i]) swap(s[i], s[r[i]]);
for(int i = ; i < n; i <<= ) {
Cp wn(cos(Pi / i), f * sin(Pi / i));
for(int j = ; j < n; j += (i << )) {
Cp w(, );
for(int k = ; k < i; ++ k) {
Cp x = s[j + k], y = w * s[j + k + i];
s[j + k] = x + y;
s[j + k + i] = x - y;
w = w * wn;
}
}
}
if(f == -)
for(int i = ; i < n; ++ i)
s[i].r /= n;
} ll Manacher(char *s, int len) {
int l = ; ll res = ;
Ma[l ++] = '$';
Ma[l ++] = '#';
for(int i = ; i < len; ++ i) {
Ma[l ++] = s[i];
Ma[l ++] = '#';
}
Ma[l] = '!';
int Mx = , id = ;
for(int i = ; i < l; ++ i) {
if(Mx > i) {
Mp[i] = min(Mp[ * id - i], (ll)Mx - i);
}
else {
Mp[i] = ;
}
while(Ma[i + Mp[i]] == Ma[i - Mp[i]]) Mp[i] ++;
if(i + Mp[i] > Mx) {
Mx = i + Mp[i];
id = i;
}
res += (Mp[i] >> ); res %= mod;
}
return res;
} int main() {
ll ans = , tmp;
scanf("%s", ss);
n = strlen(ss); lens = strlen(ss);
for(int i = ; i < n; ++ i) {
if(ss[i] == 'a')
a[i].r = , b[i].r = ;
else a[i].r = , b[i].r = ;
}
m = (n << ) - ;
for(n = ; n <= m; n <<= ) l ++;
for(int i = ; i < n; ++ i) r[i] = (r[i >> ] >> ) |((i & ) << (l - ));
DFT(a, ); DFT(b, );
for(int i = ; i < n; ++ i) {
a[i] = a[i] * a[i];
b[i] = b[i] * b[i];
}
DFT(a, -); DFT(b, -);
for(int i = ; i <= n; ++ i) {
t1[i] = (ll) (a[i].r + 0.5);
t2[i] = (ll) (b[i].r + 0.5);
}
for(int i = ; i < n; ++ i) {
t1[i] += t2[i];
}
tmp = Manacher(ss, strlen(ss));
p[] = ;
for(int i = ; i <= lens; ++ i)
p[i] = p[i - ] * % mod;
lens = lens + lens - ;
for(int i = ; i < lens; ++ i) {
if(i & ) {
ans = (ans + p[t1[i] >> ] - ) % mod;
}
else {
ans = (ans + (p[(t1[i] - ) >> ] << ) - ) % mod;
}
}
ans = (ans - tmp) % mod;
while(ans < ) {
ans += mod;
ans %= mod;
}
printf("%lld\n", ans);
return ;
}

万径人踪灭

题目4 BZOJ3028

首先很高兴的表示这里的汉堡是承德的。然后表示如果会生成函数的话这就是个输入输出题。

系数是种类,指数是数量性质。

如下图:

FFT与多项式、生成函数题目泛做

然后就没有然后了。知道答案就考虑输入和输出了。表示0ms过没有压力。这题如果你要是写个搜索。。。。。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <algorithm>
#include <cctype> using namespace std;
const int N = + ;
const int mod = ;
typedef long long ll; ll n; inline ll read() {
ll x = ;
char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)) {
x = x * + c - '';
x %= mod;
c = getchar();
}
return x;
} int main() {
n = read();
n = n * (n + ) * (n + );
n /= ;
n %= mod;
printf("%lld\n", n);
return ;
}

3028