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

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

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

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

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

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

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

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

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

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

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

当前复杂度 $O(nm\log m)$

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

当前复杂度 $O(m\log m\log 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\n", ans);
134      
135     #ifndef ONLINE_JUDGE
136         fclose(stdin);
137         fclose(stdout);
138     #endif
139     return 0;
140 }
3992_Gromah

 

posted @ 2015-04-16 09:11  Gromah  阅读(1396)  评论(3编辑  收藏  举报