zoukankan      html  css  js  c++  java
  • Luogu4191 [CTSC2010]性能优化【多项式,循环卷积】

    题目描述:设$A,B$为$n-1$次多项式,求$A*B^C$在系数模$n+1$,长度为$n$的循环卷积。

    数据范围:$nleq 5*10^5,Cleq 10^9$,且$n$的质因子不超过7,$n+1$为质数。


    这就是一个循环卷积,在$n=2^k$的情况下可以直接使用FFT/NTT,但是这里不行。

    由于$n$的质因子很小,设$n=2^{k_1}*3^{k_2}*5^{k_3}*7^{k_4}$,我们考虑将$n$分治为$p$份(NTT就是$p=2$的情况,这里$p=2,3,5,7$)

    $$F(omega_n^i)=sum_{i=0}^{p-1}omega_n^iF_i(omega_{frac{n}{p}}^i)$$

    设$a_i=F(x)[x^i]$

    $$F_r(x)=sum_{i}a_{ip+r}x^i$$

    而$rev$数组其实就是把模$p$同余的放在一起。

    NTT的逆变换就是把次数上的$i$改成$-i$,不过代码实现里面我直接写了对$A[1:n-1]$进行reverse(这里说的就是反序)

     1 #include<bits/stdc++.h>
     2 #define Rint register int
     3 using namespace std;
     4 typedef long long LL;
     5 const int N = 500003;
     6 int n, C, mod, pri[N], tot, Wn[N];
     7 inline void add(int &a, int b){a += b; if(a >= mod) a -= mod;}
     8 inline int kasumi(int a, int b){
     9     int res = 1;
    10     while(b){
    11         if(b & 1) res = (LL) res * a % mod;
    12         a = (LL) a * a % mod;
    13         b >>= 1;
    14     }
    15     return res;
    16 }
    17 inline void factor(int n){
    18     for(Rint i = 2;i * i <= n;i ++)
    19         if(!(n % i)) pri[++ tot] = i, n /= i, -- i;
    20     if(n > 1) pri[++ tot] = n;
    21 }
    22 inline int primitive(){
    23     for(Rint i = 2;;i ++){
    24         bool flag = true;
    25         for(Rint j = 1;j <= tot && flag;j ++)
    26             if(kasumi(i, n / pri[j]) == 1) flag = false;
    27         if(flag) return i;
    28     }
    29 }
    30 int a[N], b[N], tmp[N];
    31 inline void Rev(int *A){
    32     for(Rint i = tot, block = n;i;block /= pri[i], i --){
    33         for(Rint num = 0, j = 0;j < n;j += block)
    34             for(Rint k = 0;k < pri[i];k ++)
    35                 for(Rint l = 0;l < block;l += pri[i])
    36                     tmp[num ++] = A[j + k + l];
    37         for(Rint i = 0;i < n;i ++) A[i] = tmp[i];
    38     }
    39 }
    40 inline void NTT(int *A, int type){
    41     Rev(A);
    42     for(Rint i = 1, block = 1;i <= tot;i ++){
    43         int mid = block, wi = Wn[n / (block *= pri[i])];
    44         for(Rint j = 0;j < n;j ++) tmp[j] = 0;
    45         for(Rint j = 0;j < n;j += block){
    46             int wk = 1;
    47             for(Rint k = 0;k < block;k ++){
    48                 for(Rint l = k % mid, w = 1;l < block;l += mid, w = (LL) w * wk % mod)
    49                     add(tmp[j + k], (LL) w * A[j + l] % mod);
    50                 wk = (LL) wk * wi % mod;
    51             }
    52         }
    53         for(Rint j = 0;j < n;j ++) A[j] = tmp[j];
    54     }
    55     if(type == -1){
    56         std :: reverse(A + 1, A + n);
    57         for(Rint i = 0;i < n;i ++)
    58             A[i] = (LL) A[i] * n % mod;
    59     }
    60 }
    61 int main(){
    62     scanf("%d%d", &n, &C); mod = n + 1;
    63     for(Rint i = 0;i < n;i ++) scanf("%d", a + i);
    64     for(Rint i = 0;i < n;i ++) scanf("%d", b + i);
    65     factor(n);
    66     Wn[0] = 1; Wn[1] = primitive();
    67     for(Rint i = 2;i <= n;i ++) Wn[i] = (LL) Wn[i - 1] * Wn[1] % mod;
    68     NTT(a, 1); NTT(b, 1);
    69     for(Rint i = 0;i < n;i ++)
    70         a[i] = (LL) a[i] * kasumi(b[i], C) % mod;
    71     NTT(a, -1);
    72     for(Rint i = 0;i < n;i ++)
    73         printf("%d
    ", a[i]);
    74 }
    Luogu4191
  • 相关阅读:
    c++学习--面向对象一实验
    c++学习--面向对象一
    c#学习
    Linux安全之SSH 密钥创建及密钥登录,禁止密码登陆
    laravel 5.5 跨域问题 并且laravel的跨域 Access-Control-Allow-Origin 报错的坑
    安装 lnmp
    微信小程序-聊天功能下拉加载更多数据(历史聊天内容出现在顶部)
    简单实现小程序view拖拽功能
    mysql 常用命令
    有感而发——写给曼曼的信
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/10991952.html
Copyright © 2011-2022 走看看