FFT初步学习小结

来源:互联网 发布:看现货黄金数据的网址 编辑:程序博客网 时间:2024/05/02 02:35

FFT其实没什么需要特别了解的,了解下原理,(特别推荐算法导论上面的讲解),模板理解就行了。重在运用吧。

处理过程中要特别注意精度。

 

先上个练习的地址吧:

http://vjudge.net/vjudge/contest/view.action?cid=53596#overview

Problem A A * B Problem Plus

A*B的大数乘法,似乎大数模拟乘法不行的,得用FFT优化到nlogn,将一个数AnAn-1....A1A0,看做An*10^n+An-1*10^n-1+....A1*10+A0*10^0,这样就可以将两个数相乘当成多项式乘法了。

代码:

  1 #include <cstdio>  2 #include <iostream>  3 #include <cstring>  4 #include <string>  5 #include <cstdlib>  6 #include <algorithm>  7 #include <vector>  8 #include <cmath>  9 #include <queue> 10 #include <map> 11 #include <set> 12 #include <complex> 13 #define pb push_back 14 #define in freopen("solve_in.txt", "r", stdin); 15 #define out freopen("solve_out.txt", "w", stdout); 16 #define pi (acos(-1.0)) 17 #define bug(x) printf("line %d :>>>>>>>>>>>>>>>\n", x); 18 #define pb push_back 19 using namespace std; 20 #define esp 1e-8 21  22 typedef complex<double> CD; 23 const int maxn = 50000+100; 24 char s1[maxn], s2[maxn]; 25  26 struct Complex{ 27     double x, y; 28     Complex(){} 29     Complex(double x, double y):x(x), y(y){} 30 }; 31 Complex operator + (const Complex &a, const Complex &b){ 32     Complex c; 33     c.x = a.x+b.x; 34     c.y = a.y+b.y; 35     return c; 36 } 37 Complex operator - (const Complex &a, const Complex &b){ 38     Complex c; 39     c.x = a.x-b.x; 40     c.y = a.y-b.y; 41     return c; 42 } 43 Complex operator * (const Complex &a, const Complex &b){ 44     Complex c; 45     c.x = a.x*b.x-a.y*b.y; 46     c.y = a.x*b.y+a.y*b.x; 47     return c; 48 } 49  50 inline void FFT(vector<Complex> &a, bool inverse) 51 { 52     int n = a.size(); 53     for(int i = 0, j = 0; i < n; i++) 54     { 55         if(j > i) 56             swap(a[i], a[j]); 57         int k = n; 58         while(j & (k>>=1)) j &= ~k; 59         j |= k; 60     } 61     double PI = inverse ? -pi : pi; 62     for(int step = 2; step <= n; step <<= 1) 63     { 64         double alpha = 2*PI/step; 65         Complex wn(cos(alpha), sin(alpha)); 66         for(int k = 0; k < n; k += step) 67         { 68             Complex w(1, 0); 69             for(int Ek = k; Ek < k+step/2; Ek++) 70             { 71                 int Ok = Ek + step/2; 72                 Complex u = a[Ek]; 73                 Complex t = a[Ok]*w; 74                 a[Ok] = u-t; 75                 a[Ek] = u+t; 76                 w = w*wn; 77             } 78         } 79     } 80     if(inverse) 81         for(int i = 0; i < n; i++) 82             a[i].x = (a[i].x/n); 83 } 84 vector<double> operator * (const vector<double> &v1, const vector<double> &v2) 85 { 86     int S1 = v1.size(), S2 = v2.size(); 87     int S = 2; 88     while(S < S1+S2) S <<= 1; 89     vector<Complex> a(S), b(S); 90     for(int i = 0; i < S; i++) 91         a[i].x = a[i].y = b[i].x = b[i].y = 0.0; 92     for(int i = 0; i < S1; i++) 93         a[i].x = v1[i]; 94     for(int i = 0; i < S2; i++) 95         b[i].x = v2[i]; 96     FFT(a, false); 97     FFT(b, false); 98     for(int i = 0; i < S; i++) 99         a[i] = a[i] * b[i];100     FFT(a, true);101     vector<double> res(S1+S2-1, 0.0);102     for(int i = 0; i < S1+S2-1; i++)103         res[i] = a[i].x;104     return res;105 }106 int ans[maxn*2+100];107  vector<double > v1, v2;108 int main()109 {110 111     while(scanf("%s%s", s1, s2) != -1)112     {113 114         v1.clear();115         v2.clear();116         int len1 = strlen(s1);117         int len2 = strlen(s2);118         for(int i = 0; s1[i]; i++)119             v1.pb((double)(s1[len1-1-i]-'0'));120         for(int i = 0; s2[i]; i++)121             v2.pb((double)(s2[len2-1-i]-'0'));122         v1 = v1*v2;123         memset(ans, 0, sizeof(ans));124         int carry = 0, top = 0;125         for(int i = 0; i < v1.size(); i++){126             carry += (int)(v1[i]+0.5);127             ans[top++] = carry%10;128             carry /= 10;129         }130         while(carry){131             ans[top++] = carry%10;132             carry /= 10;133         }134         while(top)135         {136             if(ans[top])137                 break;138             top--;139         }140         for(int i = top; i >= 0; i--)141             printf("%d", ans[i]);142         cout<<endl;143     }144     return 0;145 }
View Code

 

Problem B 3-idiots

题意:给出一系列边长,问从中选出3条边构成三角形的概率。

分析:首先求出任意两边之和相同的取法有多少种,用每种长度边的数目作系数,FFT即可,然后就是去重了。

对所有边长排序,对于第i条边,sum[i]表示两边之和大于a[i]的边的对数,减去特殊情况,

1.两边均大于a[i],

2,两边一个大于a[i],

3,两边中包含a[i]。

代码:

  1 #include <cstdio>  2 #include <iostream>  3 #include <cstring>  4 #include <string>  5 #include <cstdlib>  6 #include <algorithm>  7 #include <vector>  8 #include <cmath>  9 #include <queue> 10 #include <map> 11 #include <set> 12 #include <complex> 13 #define pb push_back 14 #define in freopen("solve_in.txt", "r", stdin); 15 #define out freopen("solve_out.txt", "w", stdout); 16 #define pi (acos(-1.0)) 17 #define bug(x) printf("line %d :>>>>>>>>>>>>>>>\n", x); 18 #define pb push_back 19 using namespace std; 20 #define esp 1e-8 21  22 typedef complex<double> CD; 23 const int maxn = 100000+100; 24 struct Complex 25 { 26     double x, y; 27     Complex() {} 28     Complex(double x, double y):x(x), y(y) {} 29 }; 30 Complex operator + (const Complex &a, const Complex &b) 31 { 32     Complex c; 33     c.x = a.x+b.x; 34     c.y = a.y+b.y; 35     return c; 36 } 37 Complex operator - (const Complex &a, const Complex &b) 38 { 39     Complex c; 40     c.x = a.x-b.x; 41     c.y = a.y-b.y; 42     return c; 43 } 44 Complex operator * (const Complex &a, const Complex &b) 45 { 46     Complex c; 47     c.x = a.x*b.x-a.y*b.y; 48     c.y = a.x*b.y+a.y*b.x; 49     return c; 50 } 51 inline void FFT(vector<Complex> &a, bool inverse) 52 { 53     int n = a.size(); 54     for(int i = 0, j = 0; i < n; i++) 55     { 56         if(j > i) 57             swap(a[i], a[j]); 58         int k = n; 59         while(j & (k>>=1)) j &= ~k; 60         j |= k; 61     } 62     double PI = inverse ? -pi : pi; 63     for(int step = 2; step <= n; step <<= 1) 64     { 65         double alpha = 2*PI/step; 66         Complex wn = Complex(cos(alpha), sin(alpha)); 67         for(int k = 0; k < n; k += step) 68         { 69             Complex w(1, 0); 70             for(int Ek = k; Ek < k+step/2; Ek++) 71             { 72                 int Ok = Ek + step/2; 73                 Complex u = a[Ek]; 74                 Complex t = w*a[Ok]; 75                 a[Ek] = u+t; 76                 a[Ok] = u-t; 77                 w = wn*w; 78             } 79  80         } 81     } 82     if(inverse) 83         for(int i = 0; i < n; i++) 84             a[i].x = a[i].x/n; 85 } 86  87 vector<double> operator * (const vector<double> &v1, const vector<double> &v2) 88 { 89     int S1 = v1.size(), S2 = v2.size(); 90     int S = 2; 91     while(S < S1+S2) S <<= 1; 92     vector<Complex> a(S, Complex(0.0, 0.0)), b(S, Complex(0.0, 0.0)); 93     for(int i = 0; i < S1; i++) 94         a[i].x = v1[i]; 95     for(int i = 0; i < S2; i++) 96         b[i].x = v2[i]; 97     FFT(a, false); 98     FFT(b, false); 99     for(int i = 0; i < S; i++)100         a[i] = a[i] * b[i];101     FFT(a, true);102     vector<double> res(S1+S2-1, 0.0);103     for(int i = 0; i < S1+S2-1; i++)104         res[i] = a[i].x;105     return res;106 }107 int a[maxn];108 typedef long long LL;109 LL sum[maxn<<1];110 typedef long long LL;111 int n;112 int main()113 {114 in115     int T;116     for(int t = scanf("%d", &T); t <= T; t++)117     {118         LL ans =0;119         scanf("%d", &n);120         int mx = 0;121         for(int i = 0; i < (maxn<<1); i++)122             sum[i] = 0;123         for(int i = 0; i < n;  i++)124         {125             scanf("%d", &a[i]);126             sum[a[i]]++;127             mx = max(a[i], mx);128         }129         int tmp = 2;130         while(tmp < 2*(mx+1)) tmp <<= 1;//上界 是mx + 1!131         vector<Complex> v2(tmp, Complex(0.0, 0.0));132         for(int i = 0; i <= mx; i++)133             v2[i] = (Complex((double)sum[i], 0.0));134         FFT(v2, 0);135 136         for(int i = 0; i < v2.size(); i++)137         {138             v2[i] = v2[i]*v2[i];139         }140         FFT(v2, 1);141         for(int i = 0; i <= mx*2; i++)142         {143             sum[i] = (LL)(v2[i].x+0.5);144         }145         for(int i = 0; i < n; i++)146             sum[a[i]*2]--;147         for(int i = 0; i <= 2*mx; i++)148             sum[i] /= 2;149         for(int i = 1; i <= 2*mx; i++)150             sum[i] += sum[i-1];151         sort(a, a+n);152         for(int i = 0; i < n; i++)153         {154             ans += (sum[mx*2]-sum[a[i]]);155             ans -= ((LL)(n-i-1)*(n-i-2)/2 + (n-1) + (LL)i*(n-1-i));//注意用long long保证精度156         }157         printf("%.7f\n", 1.0*ans/((LL)n*(n-1)*(n-2)/6));158     }159     return 0;160 }
View Code

Problem C K-neighbor substrings

给定A,B两个01串,求A中和B串长度相同的且哈密顿距离不超过K的不同子串个数。

分析:

求一个串和另一个串的哈密顿距离,也就是对应位置字符不同的个数,长度-同为1-同为0就是结果了。怎么样找同为1或者同为0的个数呢?由于当且仅当同为1,相乘结果为1,所以将B串反转,那么作FFT,对应系数为1表示相应位置同为1,然后统计系数的和就是两串同为1个数。同为0的个数计算也很简单,只需要将B串翻转一下,0变1,1变0,同样FFT就行了。

由于题目要求不同子串的个数,利用Hash就可以了。

代码:

  1 #include <cstdio>  2 #include <iostream>  3 #include <cstring>  4 #include <string>  5 #include <cstdlib>  6 #include <algorithm>  7 #include <vector>  8 #include <cmath>  9 #include <queue> 10 #include <map> 11 #include <set> 12 #include <bitset> 13 #include <complex> 14 #define pb push_back 15 #define in freopen("solve_in.txt", "r", stdin); 16 #define out freopen("solve_out.txt", "w", stdout); 17 #define pi (acos(-1.0)) 18 #define bug(x) printf("line %d :>>>>>>>>>>>>>>>\n", x); 19 #define pb push_back 20 #define esp 1e-8 21 using namespace std; 22  23 typedef long long LL; 24 typedef unsigned long long ULL; 25 typedef map<ULL, int> MPLL; 26 const int maxn = 100000+100; 27 const int bb = 100009; 28 unsigned long long Hash[maxn], sum[maxn]; 29 MPLL mps; 30 bitset<maxn> b[2]; 31 int n, m, K; 32 struct Complex 33 { 34     double x, y; 35     Complex() {} 36     Complex(double x, double y):x(x), y(y) {} 37 }; 38 Complex operator + (const Complex &a, const Complex &b) 39 { 40     Complex c; 41     c.x = a.x+b.x; 42     c.y = a.y+b.y; 43     return c; 44 } 45 Complex operator - (const Complex &a, const Complex &b) 46 { 47     Complex c; 48     c.x = a.x-b.x; 49     c.y = a.y-b.y; 50     return c; 51 } 52 Complex operator * (const Complex &a, const Complex &b) 53 { 54     Complex c; 55     c.x = a.x*b.x-a.y*b.y; 56     c.y = a.x*b.y+a.y*b.x; 57     return c; 58 } 59 inline void FFT(vector<Complex> &a, bool inverse) 60 { 61     int n = a.size(); 62     for(int i = 0, j = 0; i < n; i++) 63     { 64         if(j > i) 65             swap(a[i], a[j]); 66         int k = n; 67         while(j & (k>>=1)) j &= ~k; 68         j |= k; 69     } 70     double PI = inverse ? -pi : pi; 71     for(int step = 2; step <= n; step <<= 1) 72     { 73         double alpha = 2*PI/step; 74         Complex wn = Complex(cos(alpha), sin(alpha)); 75         for(int k = 0; k < n; k += step) 76         { 77             Complex w(1, 0); 78             for(int Ek = k; Ek < k+step/2; Ek++) 79             { 80                 int Ok = Ek + step/2; 81                 Complex u = a[Ek]; 82                 Complex t = w*a[Ok]; 83                 a[Ek] = u+t; 84                 a[Ok] = u-t; 85                 w = wn*w; 86             } 87  88         } 89     } 90     if(inverse) 91         for(int i = 0; i < n; i++) 92             a[i].x = a[i].x/n+esp; 93 } 94 int x[maxn]; 95  96 void go(int S1, int S2) 97 { 98     int S = 2; 99     while(S < S1+S2) S <<= 1;100     vector<Complex> sa(S, Complex(0.0, 0.0)), sb(S, Complex(0.0, 0.0));101     for(int i = 0; i < S1; i++)102         sa[i].x = b[0][i];103     for(int i = 0; i < S2; i++)104         sb[i].x = b[1][i];105     FFT(sa, false);106     FFT(sb, false);107     for(int i = 0; i < S; i++)108         sa[i] = sa[i] * sb[i];109     FFT(sa, true);110     for(int i = 0; i <= n-m; i++)111     {112         x[i] += round(sa[i+m-1].x);113     }114 }115 void solve()116 {117     int ans = 0;118     go(n, m);119     b[0].flip();120     b[1].flip();121     go(n, m);122     for(int i = 0; i <= n-m; i++)123     {124         if(m-x[i] <= K)125         {126             int ok = 0;127             for(int k = 0; k < 1; k++)128             {129                 ULL tmp = Hash[i]-Hash[i+m]*sum[m];130                 if(mps.count(tmp))131                 {132                     ok++;133                 }134             }135             if(ok == 0)136             {137                 ans++;138                 mps[Hash[i]-Hash[i+m]*sum[m]] = 1;139 //                mps[1][Hash[1][0][i]-Hash[1][0][i+m]*sum[1][m]] = 1;140             }141         }142     }143     printf("%d\n", ans);144 }145 char A[maxn], B[maxn];146 void pre()147 {148     sum[0] = 1;149     for(int i = 1; i < maxn; i++)150         sum[i] = sum[i-1]*bb;151 }152 153 154 int main()155 {156 157     pre();158     int kase = 0;159     while(scanf("%d", &K), K >= 0)160     {161         printf("Case %d: ", ++kase);162         mps.clear();163         Hash[n] = 0;164         scanf("%s%s", A, B);165         n = strlen(A), m = strlen(B);166         for(int i = n-1; i >= 0; i--)167         {168             x[i] = 0;169             int t = A[i]-'a';170             b[0][i] = t;171             Hash[i] = Hash[i+1]*bb+t;172         }173         for(int i = m-1; i >= 0; i--)174         {175             int t = B[i]-'a';176             b[1][m-1-i] = t;177         }178         solve();179     }180     return 0;181 }
View Code

 

Problem D Linear recursive sequence

f(k)  = 0(k <=0)

f(k) = af(k-p)+bf(k-q) 

a,b,k<=10^9, p < q <= 10^4

分析:

具体用到了叉姐的论文《矩阵乘法递推的优化》,其实总结起来就是一个式子,W^i = b1*W^k-1+b2*W^k-2+......bk*E,也就是任何一个W^i都可以表示成E,W^1,W^2,

.....W^k-1的线性组合。求f(n)也就是求出f(n)对应的W^i,(i = n-k+1), 实际就是多次求一个多项式乘法,每次复杂度O(k^2), 这样可以将矩阵乘法优化到k^2log(n)。

但是本题范围较大即使k^2log(n)也不够优化,而且递推系数只有2个,其他都为0,因此可以用FFT加速多项式乘法,O(qlogqlogn)已经很优化了。

代码:

  1 #pragma comment(linker, "/STACK:16777216")  2 #include <cstdio>  3 #include <iostream>  4 #include <cstring>  5 #include <string>  6 #include <cstdlib>  7 #include <algorithm>  8 #include <vector>  9 #include <cmath> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #include <bitset> 14 #include <complex> 15 #define inf 0x0f0f0f0f 16 #define pb push_back 17 #define in freopen("solve_in.txt", "r", stdin); 18 #define out freopen("solve_out.txt", "w", stdout); 19 #define pi (acos(-1.0)) 20 #define bug(x) printf("line %d :>>>>>>>>>>>>>>>\n", x); 21 #define pb push_back 22 #define esp 1e-8 23 typedef long long LL; 24 using namespace std; 25  26 const int M = 119; 27 int n, p, q, a, b; 28  29 struct Complex { 30     double x, y; 31     Complex() {} 32     Complex(double x, double y):x(x), y(y) {} 33     Complex operator + (const Complex &o)const { 34         return Complex(x+o.x, y+o.y); 35     } 36     Complex operator - (const Complex &o)const { 37         return Complex(x-o.x, y-o.y); 38     } 39     Complex operator * (const Complex &o)const { 40         return Complex(x*o.x-y*o.y, y*o.x+x*o.y); 41     } 42 }; 43 void add(double &x, double y) { 44     long long a = (LL)(x+.5), b = (LL)(y+.5); 45     a += b; 46     a%=M; 47     x = (double)a; 48 } 49 void FFT(vector<Complex> &a, bool inverse) { 50     int nn = a.size(); 51     for(int i =0, j = 0; i < nn; i++) { 52         if(j > i) 53             swap(a[i], a[j]); 54         int k = nn; 55         while(j &(k >>= 1)) j &=~k; 56         j |= k; 57     } 58     double PI = inverse ? -pi : pi; 59     for(int step = 2; step <= nn; step <<= 1) { 60         Complex wn(cos(PI*2/step), sin(PI*2/step)); 61         for(int j = 0; j < nn; j += step) { 62             Complex w(1, 0); 63             for(int Ek = j; Ek < j+step/2; Ek++) { 64                 int Ok = Ek + step/2; 65                 Complex u = a[Ek]; 66                 Complex t = w*a[Ok]; 67                 a[Ek] = u+t; 68                 a[Ok] = u-t; 69                 w = w*wn; 70             } 71         } 72     } 73     if(inverse) 74         for(int i = 0; i < nn; i++) 75             a[i].x = a[i].x/nn; 76 } 77 vector<double> operator *(const vector<double> &v1, const vector<double> &v2) { 78     int S1 = v1.size(); 79     int S2 = v2.size(); 80     int S = 2; 81     while(S < S1+S2) S <<= 1; 82     vector<Complex> aa(S, Complex(0.0, 0.0)), ab(S, Complex(0.0, 0.0)); 83     for(int i = 0; i < S1; i++) 84         aa[i].x = v1[i]; 85     for(int i = 0; i < S2; i++) 86         ab[i].x = v2[i]; 87     FFT(aa, false); 88     FFT(ab, false); 89     for(int i = 0; i < S; i++) 90         aa[i] = aa[i]*ab[i]; 91     FFT(aa, true); 92     vector<double> res(S1+S2-1, 0.0); 93     for(int i = 0; i < S1+S2-1; i++) { 94         res[i] = aa[i].x; 95 //        cout<<aa[i].y<<endl; 96 //        cout<<res[i]<<endl; 97     } 98     for(int i = S1+S2-2; i >= q; i--) { 99         add(res[i-p], a*res[i]);100         add(res[i-q], b*res[i]);101     }102     res.resize(q);103     return res;104 }105 const int maxn = (int)3e4+100;106 107 int h[maxn];108 void calPre() {109     memset(h, 0, sizeof h);110     h[0] = 1;111     for(int i = 1; i < 2*q-1; i++) {112         if(i<=p) h[i] = (h[i]+a)%M;113         else h[i] = (h[i]+a*h[i-p])%M;114         if(i-q <= 0)  h[i] = (h[i]+b)%M;115         else h[i] = (h[i]+b*h[i-q])%M;116     }117 }118 int main() {119 120     while(scanf("%d%d%d%d%d", &n, &a, &b, &p, &q) == 5) {121         a %= M;122         b %= M;123         calPre();124         if(n < q) {125             cout<<h[n]<<endl;126             continue;127         }128         n=n-q+1;129         vector<double> Ma(q, 0.0), base(q, 0.0);130         Ma[0] = 1.0;131         base[1] = 1.0;132         while(n) {133             if(n&1) {134                 Ma = Ma*base;135             }136             base = base*base;137             n>>=1;138         }139 ////        Ma = Ma*base;140 ////        cout<<base[0]<<base[1]<<endl;141 ////        cout<<Ma[0]<<Ma[1]<<endl;142         double res = 0;143         for(int i = 0; i < q; i++) {144             add(res, (Ma[i]*h[q-1+i]));145         }146         cout<<(int)(res+.5)<<endl;147     }148     return 0;149 }
View Code

HDU G++超时,C++2000ms,真是无力了。还有连叉姐标程C++都会超时,G++才能过。不过好像极端数据,标程和我的代码都不能再规定时间跑完,大概15s左右?所以说数据还是很水的。

Problem E Cipher Message 3

题意:给定n个8二进制串,和m个8位二进制串构成2个序列,要求在n个串的序列中找到连续的一段,使得和m个二进制串匹配,匹配的意思是两个序列中对应的二进制串前7位相同,后面一位可以不同,但是会有额外的花费,求最后花费最小的一个匹配序列,而且要求该序列在n中尽量靠左。

分析:

训练赛时遇到的一道题,当时不会FFT,甚至不知道这玩意在竞赛里还能干啥,首先利用KMP找出所有能够匹配的位置,当时知道怎么找花费最小的了。利用FFT求出两个串在各个位置开始的哈密顿距离就可以了。转化和上面C题一样。

代码:

  1 #include <cstdio>  2 #include <iostream>  3 #include <cstring>  4 #include <string>  5 #include <cstdlib>  6 #include <algorithm>  7 #include <vector>  8 #include <queue>  9 #include <ctime> 10 #include <map> 11 #include <set> 12 #include <cmath> 13 #include <bitset> 14 #define pb push_back 15 #define in freopen("solve_in.txt", "r", stdin); 16 #define out freopen("solve_out.txt", "w", stdout); 17 #define pi (acos(-1.0)) 18 #define bug(x) printf("line %d :>>>>>>>>>>>>>>>\n", x); 19 #define pb push_back 20 using namespace std; 21 #define esp 1e-8 22  23 const int maxn = 250000+100; 24 int sa[maxn], sb[maxn]; 25 int n, m; 26 int x[maxn]; 27 bitset<maxn> da, db; 28 struct Complex 29 { 30     double x, y; 31     Complex() {} 32     Complex(double x, double y):x(x), y(y) {} 33     inline Complex operator + (const Complex &b)const 34     { 35         return Complex(x+b.x, y+b.y); 36     } 37     inline Complex operator - ( const Complex &b)const 38     { 39         return Complex(x-b.x, y-b.y); 40     } 41     inline Complex operator * (const Complex &b)const 42     { 43         return Complex(x*b.x-y*b.y, x*b.y+y*b.x); 44     } 45 }; 46  47  48 inline void FFT(vector<Complex> &a, bool inverse) 49 { 50     int n = a.size(); 51     for(int i = 1, j = n/2; i < n-1; i++) 52     { 53         if(j > i) 54             swap(a[i], a[j]); 55         int k = n>>1; 56         while(j >= k) 57         { 58             j-=k; 59             k >>= 1; 60         } 61         j += k; 62     } 63     double PI = inverse ? -pi : pi; 64     for(int step = 2; step <= n; step <<= 1) 65     { 66         double alpha = 2*PI/step; 67         Complex wn(cos(alpha), sin(alpha)); 68  69         for(int k = 0; k < n; k+=step) 70         { 71             Complex w(1, 0); 72             for(int j = k; j < k+step/2; j++) 73             { 74  75                 Complex u = a[j]; 76                 Complex t = w*a[j+step/2]; 77                 a[j] = u+t; 78                 a[j+step/2] = u-t; 79                 w = w*wn; 80             } 81         } 82     } 83     if(inverse) 84         for(int i = 0; i < n; i++) 85             a[i].x = a[i].x/n; 86 } 87 void go() 88 { 89     int S1 = n, S2 = m; 90     int tmp = max(S1, S2); 91     int S = 2; 92     while(S < S1+S2) S <<= 1; 93     vector<Complex> a(S, Complex(0.0, 0.0)), b(S, Complex(0.0, 0.0)); 94     for(int i = 0; i < S1; i++) 95         a[i].x = da[i]; 96     for(int i = 0; i < S2; i++) 97         b[i].x = db[i]; 98     FFT(a, false); 99     FFT(b, false);100     for(int i = 0; i < S; i++)101     {102         Complex c;103         c.x = (a[i].x*b[i].x)-(a[i].y*b[i].y);104         c.y = (a[i].x*b[i].y)+(a[i].y*b[i].x);105         a[i] = c;106 //        a[i] = a[i]*b[i];107     }108     FFT(a, true);109     for(int i = 0; i <= n-m; i++)110         x[i] += round(esp+a[i+m-1].x);111 }112 int f[maxn];113 int match[maxn];114 int cnt = 0;115 void getFail(int a[], int n)116 {117     f[0] = f[1] = 0;118     int j;119     for(int i = 1; i < n; i++)120     {121         j = f[i];122         while(j && a[i] != a[j]) j = f[j];123         f[i+1] = (a[i] == a[j] ? j+1 : 0);124     }125 }126 void KMP(int T[], int P[], int n, int m)127 {128     getFail(P, m);129     int j = 0;130     for(int i = 0; i < n; i++)131     {132         while(j && T[i] != P[j]) j = f[j];133         if(T[i] == P[j]) j++;134         if(j == m)135         {136             match[cnt++] = i-m+1;137         }138     }139 }140 141 char bit[10];142 void input()143 {144     for(int i = 0; i < n; i++)145     {146         scanf("%s", bit);147         da[i] = bit[7]-'0';148         for(int ii = 0; ii < 7; ii++)149             sa[i] = sa[i]*2+bit[ii]-'0';150     }151     for(int i = 0; i < m; i++)152     {153         scanf("%s", bit);154         db[m-1-i] = bit[7]-'0';155         for(int ii = 0; ii < 7; ii++)156             sb[i] = sb[i]*2+bit[ii]-'0';157     }158     sa[n] = sb[m] = -1;159 }160 161 void solve()162 {163     srand(time(0));164     KMP(sa, sb, n, m);165     if(cnt == 0)166     {167         puts("No");168         return;169     }170     puts("Yes");171     go();172     da.flip();173     db.flip();174     go();175     int ans = m;176     int pos = 0;177     for(int i = 0; i < cnt; i++)178     {179         if(ans == 0)180             break;181         int tmp = match[i];182         if(m-x[tmp] < ans)183             ans = m-x[tmp], pos = tmp;184     }185 186     printf("%d %d\n", ans, pos+1);187 }188 int main()189 {190 191     scanf("%d%d", &n,&m);192     input();193     solve();194     return 0;195 }
View Code

其实还遇到一道题,里面也用到了FFT,HDU 4954 Permanent不过先挖个坑。

总结:FFT看上去很繁琐,了解了发现其实也就是一个很好利用的工具。很多东西要尽量主动去学习,如果之前了解过FFT,说不定遇到关键问题就不会像上面卡壳了。对于遇到的新的东西,也要沉下心来,不要只想着切自己学过的,感兴趣的知识,那绝不是进步的方法。

 

0 0