数学相关一直都好弱啊>_<
窝这个月要补一补数学啦, 先从基础的fft补起吧!
现在做了 道。
窝的fft 模板 (bzoj 2179)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #define MAXN 200005 7 #define PI M_PI 8 using namespace std; 9 struct CP{ 10 double x, y; 11 CP(){} 12 CP(double x, double y) : x(x), y(y) {} 13 inline CP operator+ (CP b) {return CP(x+b.x, y+b.y);} 14 inline CP operator- (CP b) {return CP(x-b.x, y-b.y);} 15 inline CP operator* (CP b) {return CP(x*b.x-y*b.y, x*b.y+y*b.x);} 16 }a[MAXN], b[MAXN], A[MAXN], x, y; 17 int n, N, l, dig[MAXN], ans[MAXN]; 18 char s1[MAXN], s2[MAXN]; 19 inline void dft(CP *a, int n, int f){ 20 for(int i = 0; i < n; i ++) A[i] = a[dig[i]]; 21 for(int i = 0; i < n; i ++) a[i] = A[i]; 22 for(int i = 2; i <= n; i <<= 1){ 23 CP wn(cos(2*PI/i), f*sin(2*PI/i)); 24 for(int k = 0; k < n; k += i){ 25 CP w(1, 0); 26 for(int j = 0; j < i/2; j ++) x = a[k+j], y = w*a[k+j+i/2], a[k+j]=x+y, a[k+j+i/2] = x-y, w = w*wn; 27 } 28 } 29 } 30 int main(){ 31 scanf("%d%s%s", &n, s1, s2); 32 for(int i = 0; i < n; i ++) a[i].x = s1[n-i-1]-‘0‘, b[i].x = s2[n-i-1]-‘0‘; 33 for(N = 1, l = 0; N < n; N <<= 1, l ++); N <<= 1, l ++; 34 for(int i = 0; i < N; i ++){ 35 int ret = 0, p = i; 36 for(int j = 1; j <= l; j ++) ret <<= 1, ret += (p&1), p >>= 1; 37 dig[i] = ret; 38 } 39 dft(a, N, 1), dft(b, N, 1); 40 for(int i = 0; i < N; i ++) a[i] = a[i]*b[i]; 41 dft(a, N, -1); 42 for(int i = 0; i < N; i ++) ans[i] = (int)(a[i].x / N + 0.5); 43 for(int i = 0; i < N; i ++) ans[i+1] += ans[i]/10, ans[i] %= 10; 44 l = N; while(l > 1 && ans[l-1] == 0) l --; 45 for(int i = l-1; i >= 0; i --) printf("%d", ans[i]); cout << endl; 46 return 0; 47 }
BZOJ 2194
之前做过的啦,求 c_k = Σ(a_i * b_(i-k)) (k <= i)
标准的差积形式是 i + j 一定, 现在的式子要求 i - j 一定, 容易想到把所有b的下标都乘以-1原式即转化为i+j一定了, 为了方便处理可以把所有b再加上n使得下标为非负数,即把b_i 变为 b_(n-i) 。
tips: 卷积的形式并不一定只是 k = i+j, 还有可能是 k = i-j 或者 …………
bzoj 3527: [Zjoi2014]力
之前做过的啦。 不打式子了, 是个人都会把qi乘进去, 然后原式就变成了求 E_i = Σqj/((i-j)^2) (j<i) - Σqj/((i-j)^2) (j>i)
我第一次做的时候并没有看出来这是个卷积QAQ 蠢死了QAQ
我们可以设 一个 函数 f(x) = q_x, g(x) = 1/(x^2), 然后那个式子的前一项不就是 f 和 g 的卷积了吗! 第二个式子是 当 i-j一定时候的情况, 那不就是上一题 bzoj 2194了吗,,,,然后就没了。
tips:不要拘泥于已有的数列,可以根据题目自己构造出新的函数, 需要求 F_i = Σ( f(j) 乘或除以 g(i±j) ) 的时候很有可能是卷积!!!看到 j 和 i±j 这类的关键词就应该往这边多想一想。
BZOJ 3771 Triple
之前做过的啦。给定n个物品,可以用一个/两个/三个不同的物品凑出不同的价值,求每种价值有多少种拼凑方案(顺序不同算一种) (题目大意来自popoqqq)
自己还是没有想到QAQ
这个要构建一个母函数。初步地感受母函数的应用:如果我们可以快速地计算出一次操作后每种效果有多少种产生方案(0/1),并且多次操作的效果是可以累加的,那么在用fft优化以后(效果的累加不就是卷积吗)可以比较快速地(k*nlogn)计算出k次操作后每种效果有多少种产生方案 (怎么觉得我在说的是用快速幂优化的矩阵乘法啊。。。。。)感觉的确和矩乘有点像, 不过矩乘的每次操作的状态是一个二维的数组, 因为在不同的点可以进行的操作不同, 但是 母函数只需要求出一个一维数组, 因为在应用母函数的时候当前状态 并不会影响下一步的操作
(以上皆是窝自己的口胡,等我读完具体数学的 "生成函数" 一章后再来总结吧QAQ)
tips: 见上
BZOJ 3160 万径人踪灭
给出一个只含有a和b的字符串, 求有多少个至少有一个断点(即不完全连续)的回文子序列,要求子序列选出来的每一个的位置同样必须关于任意一个位置或中缝对称。
考虑以每一个点i为中间的点所组成的符合要求的子序列,对于每一个j, 如果 s[i-j] == s[i+j] 则可以把这对字符加到子序列里, 当然也可以不加, 显然对于不同的j, 每一对字符是相互独立的, 所以以i为中点的贡献就是 2^(s[i-j]==s[i+j]的数量), 注意因为子序列不可以完全连续所以还要再减去一个可以直接manachar求出来的完全连续的回文串数量。 所以现在唯一剩下的问题就是对于每一个i, Σ (s[i-j] == s[i+j]), 因为只有a, b两种字符, 显然可以拆开来算, 设数组A使得 A_i = (s[i] == ‘a‘), 则字符a对于以i为中心贡献就是 Σ (s[j]*s[2*i-j]) , 这个显然就是一个卷积啦。
hdu 4509 3-idiot
给你三根线段, 问你有多少种可以组成三角形的方法。
做过bzoj3771后这题就是一眼题了QAQ 类似地,对于边长建出一个生成函数然后卷积一次算出由两条边组成的长度和为x的线段组有多少组然后再扫一遍第三条边就可以了。