• BZOJ 3992 [SDOI 2015] 序列统计 解题报告


    这个题最暴力的搞法就是这样的:

    设 $Dp[i][j]$ 为前 $i$ 个数乘积为 $j$ 的方案数。

    转移的话就不多说了哈。。。

    当前复杂度 $O(nm^2)$

    注意到,$M$ 是个质数,就说明 $M$ 有原根并且我们可以很快的求出来。

    于是对于 $1 ightarrow M-1$ 中的每一个数都可以表示成原根的某次幂。

    于是乘法可以转化为原根的幂的加法,

    转移的时候就相当于做多项式乘法了。

    我们再注意到,$1004535809 = 479 imes 2^{21} + 1$ 并且是个质数,原根为 $3$。

    于是转移的时候就可以用 $FFT$ 优化了。

    当前复杂度 $O(nmlog m)$

    我们再考虑,每次多项式乘法中乘的多项式都是一样的,那么是不是就可以快速幂啊?

    当前复杂度 $O(mlog mlog n)$,可以 A 掉这个题啦~

    注意那些等于 $0$ 的数。。。

    具体细节自己脑补脑补吧~

      1 #include <cmath>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <iostream>
      5 #include <algorithm>
      6 using namespace std;
      7 typedef long long LL;
      8 #define N 16384 + 5
      9 #define Mod 1004535809
     10 #define g 3
     11  
     12 int n, p, x, m, len, w, d, root, inv_len, ans;
     13 int T[N], Num[N], Pos[N];
     14 int A[N], B[N], C[N], Rev[N], e[2][N];
     15  
     16 inline int power(int u, int v, int p)
     17 {
     18     int res = 1;
     19     for (; v; v >>= 1)
     20     {
     21         if (v & 1) res = (LL) res * u % p;
     22         u = (LL) u * u % p;
     23     }
     24     return res;
     25 }
     26  
     27 inline void Init()
     28 {
     29     scanf("%d%d%d%d", &n, &p, &x, &m);
     30     for (int i = 1; i <= m; i ++)
     31         scanf("%d", T + i);
     32     for (len = p << 1; len != (len & -len); len += (len & -len)) ;
     33     for (int i = len; i > 1; i >>= 1) d ++;
     34     inv_len = power(len, Mod - 2, Mod);
     35     w = power(g, (Mod - 1) / len, Mod);
     36 }
     37  
     38 inline bool Judge(int x, int p)
     39 {
     40     for (int i = 2; i * i <= p; i ++)
     41         if ((p - 1) % i == 0 && power(x, (p - 1) / i, p) == 1) return 0;
     42     return 1;
     43 }
     44  
     45 inline int Find_Root(int p)
     46 {
     47     if (p == 2) return 1;
     48     int res = 2;
     49     for (; !Judge(res, p); res ++) ;
     50     return res;
     51 }
     52  
     53 inline void Prepare()
     54 {
     55     root = Find_Root(p);
     56     for (int i = 0; i < p - 1; i ++)
     57     {
     58         Num[i] = !i ? 1 : Num[i - 1] * root % p;
     59         Pos[Num[i]] = i;
     60     }
     61 }
     62  
     63 inline int Inc(int u, int v)
     64 {
     65     return u + v - (u + v >= Mod ? Mod : 0);
     66 }
     67  
     68 inline void FFT(int *Ar, int op)
     69 {
     70     for (int i = 0; i < len; i ++)
     71         if (Rev[i] > i) swap(Ar[i], Ar[Rev[i]]);
     72     for (int k = 1, s = 1; k < len; k <<= 1, s ++)
     73         for (int i = 0; i < len; i ++)
     74         {
     75             if (i & k) continue ;
     76             int t = (i & k - 1) << d - s;
     77             int u = Inc(Ar[i], (LL) Ar[i + k] * e[op][t] % Mod);
     78             int v = Inc(Ar[i], Mod - ((LL) Ar[i + k] * e[op][t] % Mod));
     79             Ar[i] = u, Ar[i + k] = v;
     80         }
     81 }
     82  
     83 inline void Convol(int *U, int *V)
     84 {
     85     for (int i = 0; i < len; i ++)
     86         C[i] = V[i];
     87     FFT(U, 0), FFT(C, 0);
     88     for (int i = 0; i < len; i ++)
     89         U[i] = (LL) U[i] * C[i] % Mod;
     90     FFT(U, 1);
     91     for (int i = 0; i < len; i ++)
     92         U[i] = (LL) U[i] * inv_len % Mod;
     93     for (int i = len - 1; i >= p - 1; i --)
     94     {
     95         U[i - p + 1] = Inc(U[i - p + 1], U[i]);
     96         U[i] = 0;
     97     }
     98 }
     99  
    100 inline void Solve()
    101 {
    102     A[0] = 1;
    103     for (int i = 1; i <= m; i ++)
    104     {
    105         if (T[i] == 0) continue ;
    106         B[Pos[T[i]]] ++;
    107     }
    108     for (int i = 0, inv_w = power(w, Mod - 2, Mod); i < len; i ++)
    109     {
    110         e[0][i] = !i ? 1 : (LL) e[0][i - 1] * w % Mod;
    111         e[1][i] = !i ? 1 : (LL) e[1][i - 1] * inv_w % Mod;
    112         for (int j = 0; j < d; j ++)
    113             if ((i >> j) & 1) Rev[i] += 1 << (d - j - 1);
    114     }
    115     for (; n; n >>= 1)
    116     {
    117         if (n & 1) Convol(A, B);
    118         Convol(B, B);
    119     }
    120     ans = A[Pos[x]];
    121 }
    122  
    123 int main()
    124 {
    125     #ifndef ONLINE_JUDGE
    126         freopen("sequence.in", "r", stdin);
    127         freopen("sequence.out", "w", stdout);
    128     #endif
    129      
    130     Init();
    131     Prepare();
    132     Solve();
    133     printf("%d
    ", ans);
    134      
    135     #ifndef ONLINE_JUDGE
    136         fclose(stdin);
    137         fclose(stdout);
    138     #endif
    139     return 0;
    140 }
    3992_Gromah
  • 相关阅读:
    关于冥想
    Read Later
    你追求的跟我相反
    UML for Java Programmers之dx实战
    20140525
    面试基础-语言基础篇
    面试基础-linux操作系统篇
    面试基础-数据库篇
    面试基础-计算机网络篇
    Eclipse同时编译多个cpp文件
  • 原文地址:https://www.cnblogs.com/gromah/p/4431016.html
Copyright © 2020-2023  润新知