• 洛谷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 
    ", 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("
    ");*/
    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("
    ans : ");
    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代码
  • 相关阅读:
    利用python对新浪微博用户标签进行分词并推荐相关用户
    企业微信公众平台建设指南
    微信5.0:可定制菜单栏、移动支付、公众账号付费订阅
    jquery 控件使用 讲解 连载
    网络那些事
    拒绝访问 无法删除文件的解决方法
    Ubuntu9.10下安装Maya8.5(Finish)
    Ubuntu 9.10 更新软件源列表
    [转载]PHP的Class分页
    PHP与Mysql的连接
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10253698.html
Copyright © 2020-2023  润新知