洛谷P3321 序列统计

气死了,FFT了半天发现是NTT... 1004535809 这个东西是NTT模数,原根为3。

题意:给定集合,元素的大小不超过M。用这些元素组成长为n的序列,要求乘积模M为k,求方案数。

n <= 1e9,M是质数

解:有一个10分的暴力DP...

正解首先考虑加起来模M为k。

我们可以考虑构造多项式f(x),第i项表示i是否在集合内。

那么答案就是(f(x))n的第k项系数。多项式快速幂。

这个东西的长度可能会很长,那么我们每次乘完之后就把多于M项的系数全部模到小于M。

然后这道题求的是乘积不是和....原根!

因为质数都有原根,然后两个数相乘等于原根指数相加。做完了。

注意原根的指数模的是φ(M)而不是M。还有千万不要用FFT,因为会爆double

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <cmath>
  5 
  6 typedef long long LL;
  7 const int N = 8010;
  8 const LL MO = 1004535809, g = 3;
  9 
 10 int r[N << 2], b[N], vis[N];
 11 LL f[N << 2], ans[N << 2], a[N << 2], c[N << 2];
 12 
 13 inline LL qpow(LL a, LL b) {
 14     LL ans = 1;
 15     while(b) {
 16         if(b & 1) {
 17             ans = ans * a % MO;
 18         }
 19         a = a * a % MO;
 20         b = b >> 1;
 21     }
 22     return ans;
 23 }
 24 
 25 inline void NTT(int n, LL *a, int f) {
 26     for(int i = 0; i < n; i++) {
 27         if(i < r[i]) {
 28             std::swap(a[i], a[r[i]]);
 29         }
 30     }
 31     for(int len = 1; len < n; len <<= 1) {
 32         LL Wn = qpow(g, (MO - 1) / (len << 1));
 33         if(f == -1) {
 34             Wn = qpow(Wn, MO - 2);
 35         }
 36         for(int i = 0; i < n; i += (len << 1)) {
 37             LL w = 1;
 38             for(int j = 0; j < len; j++) {
 39                 LL t = a[i + len + j] * w % MO;
 40                 a[i + len + j] = (a[i + j] - t + MO) % MO;
 41                 a[i + j] = (a[i + j] + t) % MO;
 42                 w = w * Wn % MO;
 43             }
 44         }
 45     }
 46     if(f == -1) {
 47         LL inv = qpow(n, MO - 2);
 48         for(int i = 0; i <= n; i++) {
 49             a[i] = a[i] * inv % MO;
 50         }
 51     }
 52     return;
 53 }
 54 
 55 inline int getG(int x) {
 56     for(int i = 1; i < x; i++) {
 57         memset(vis, 0, x * sizeof(int));
 58         int now = 1, fd = 0;
 59         for(int t = 1; t < x; t++) {
 60             now = now * i % x;
 61             if(vis[now]) {
 62                 fd = 1;
 63                 break;
 64             }
 65             vis[now] = t;
 66         }
 67         if(!fd) {
 68             return i;
 69         }
 70     }
 71     return -1;
 72 }
 73 
 74 int main() {
 75     int n, m, mod, k;
 76     scanf("%d%d%d%d", &n, &mod, &k, &m);
 77     for(int i = 1; i <= m; i++) {
 78         scanf("%d", &b[i]);
 79     }
 80     getG(mod);
 81     for(int i = 1; i <= m; i++) {
 82         b[i] = vis[b[i]];
 83         if(b[i]) {
 84             f[b[i]] = 1;
 85         }
 86     }
 87     k = vis[k];
 88 
 89     int len = 2, lm = 1;
 90     while(len <= ((mod - 1) << 1)) {
 91         len <<= 1;
 92         lm++;
 93     }
 94     for(int i = 1; i <= len; i++) {
 95         r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1));
 96     }
 97 
 98     /*printf("g = %d \n", g);
 99     for(int i = 1; i <= m; i++) {
100         printf("%d ", b[i]);
101     }
102     puts("");
103     for(int i = 0; i < mod; i++) {
104         printf("%d ", f[i]);
105     }
106     puts("\n");*/
107 
108     ans[0] = 1;
109     while(n) {
110         if(n & 1) {
111             for(int i = 0; i <= len; i++) {
112                 a[i] = f[i];
113                 c[i] = ans[i];
114             }
115             NTT(len, a, 1);
116             NTT(len, c, 1);
117             for(int i = 0; i <= len; i++) {
118                 c[i] = a[i] * c[i] % MO;
119             }
120             NTT(len, c, -1);
121             for(int i = 0; i <= len; i++) {
122                 ans[i] = c[i];
123             }
124             for(int i = len; i >= mod; i--) {
125                 (ans[i - mod + 1] += ans[i]) %= MO;
126                 ans[i] = 0;
127             }
128         }
129         for(int i = 0; i <= len; i++) {
130             a[i] = f[i];
131         }
132         NTT(len, a, 1);
133         for(int i = 0; i <= len; i++) {
134             a[i] = a[i] * a[i] % MO;
135         }
136         NTT(len, a, -1);
137         for(int i = 0; i <= len; i++) {
138             f[i] = a[i];
139         }
140         for(int i = len; i >= mod; i--) {
141             (f[i - mod + 1] += f[i]) %= MO;
142             f[i] = 0;
143         }
144         n >>= 1;
145         /*printf("f   : ");
146         for(int i = 0; i < mod; i++) {
147             printf("%d ", f[i]);
148         }
149         printf("\nans : ");
150         for(int i = 0; i < mod; i++) {
151             printf("%d ", ans[i]);
152         }
153         puts("");*/
154     }
155 
156     printf("%lld", ans[k]);
157     return 0;
158 }
AC代码

 

posted @ 2019-01-11 10:01  huyufeifei  阅读(152)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

ReadEra 阅读书籍

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜