zoukankan      html  css  js  c++  java
  • FFT初步学习小结

    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 :>>>>>>>>>>>>>>>
    ", 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 :>>>>>>>>>>>>>>>
    ", 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 in
    115     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
    ", 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 :>>>>>>>>>>>>>>>
    ", 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
    ", 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 :>>>>>>>>>>>>>>>
    ", 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 :>>>>>>>>>>>>>>>
    ", 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
    ", 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,说不定遇到关键问题就不会像上面卡壳了。对于遇到的新的东西,也要沉下心来,不要只想着切自己学过的,感兴趣的知识,那绝不是进步的方法。

  • 相关阅读:
    Unity NGUI 2D场景添加按钮
    EaseType缓动函数
    在没有网络的情况下用安卓手机和数据线让台式电脑上网
    面向对象编程
    static与C#中的static
    C#基础
    iSensor APP 之 摄像头调试 OV5642
    iSensor APP 之 摄像头调试 OV9655
    USB3.0之高速视频传输测试 双目相机(mt9p031、mt9m001)带宽高达300M测试 配合isensor测试 500万像素15fps
    模拟摄像头解码模块最新测试 TVP5150模块 FPGA+SDRAM+TVP5150+VGA 实现PAL AV输入 VGA视频输出
  • 原文地址:https://www.cnblogs.com/rootial/p/3920599.html
Copyright © 2011-2022 走看看