zoukankan      html  css  js  c++  java
  • [BZOJ 3992][SDOI2015]序列统计

    3992: [SDOI2015]序列统计

    Time Limit: 30 Sec  Memory Limit: 128 MB
    Submit: 2275  Solved: 1090
    [Submit][Status][Discuss]

    Description

    小C有一个集合S,里面的元素都是小于M的非负整数。他用程序编写了一个数列生成器,可以生成一个长度为N的数
    列,数列中的每个数都属于集合S。小C用这个生成器生成了许多这样的数列。但是小C有一个问题需要你的帮助:
    给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个。小C认为
    ,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi。另外,小C认为这个问题的答案可能很大
    ,因此他只需要你帮助他求出答案mod 1004535809的值就可以了。

    Input

    一行,四个整数,N、M、x、|S|,其中|S|为集合S中元素个数。
    第二行,|S|个整数,表示集合S中的所有元素。
    1<=N<=10^9,3<=M<=8000,M为质数
    0<=x<=M-1,输入数据保证集合S中元素不重复x∈[1,m-1]

    集合中的数∈[0,m-1]

    Output

    一行,一个整数,表示你求出的种类数mod 1004535809的值。

    Sample Input

    4 3 1 2
    1 2

    Sample Output

    8
    【样例说明】
    可以生成的满足要求的不同的数列有(1,1,1,1)、(1,1,2,2)、(1,2,1,2)、(1,2,2,1)、
    (2,1,1,2)、(2,1,2,1)、(2,2,1,1)、(2,2,2,2)

     

    题解

    这题的要求非常类似背包, 但是值之间做的贡献是乘积的形式. 我们考虑把它转成加法.

    怎么转加法呢? 当然是取对数了!

    离散对数哪家强? SDOI找...(划掉)

    注意到如果数列里有 $0$ 那么贡献就是 $0$, 但是题目规定要求的目标值非 $0$, 所以我们首先先把 $0$ 扔掉

    然后暴力计算出 $m$ 的一个原根, 同时处理出每个数的对数

    那么这就是一个长度为 $m-1$ 的循环卷积辣!

    然而循环卷积需要膜数有 $m-1$ 次单位根(吧), 于是只能NTT倍增爆算了...(或者博主naive?)

    参考代码

    多项式左右移操作现已加入豪华午餐

      1 #include <bits/stdc++.h>
      2 
      3 const int G=3;
      4 const int DFT=1;
      5 const int IDFT=-1;
      6 const int MAXN=550000;
      7 const int MOD=1004535809;
      8 const int INV2=(MOD+1)>>1;
      9 const int PHI=MOD-1;
     10 
     11 typedef std::vector<int> Poly;
     12 
     13 Poly Sqrt(Poly);
     14 void Read(Poly&);
     15 Poly Inverse(Poly);
     16 Poly Ln(const Poly&);
     17 Poly Exp(const Poly&);
     18 void Print(const Poly&);
     19 void NTT(Poly&,int,int);
     20 Poly Pow(const Poly&,int);
     21 Poly Integral(const Poly&);
     22 Poly Derivative(const Poly&);
     23 Poly operator*(Poly,Poly);
     24 Poly operator/(Poly,Poly);
     25 Poly operator%(Poly,Poly);
     26 Poly operator<<(const Poly&,int);
     27 Poly operator>>(const Poly&,int);
     28 Poly operator+(const Poly&,const Poly&);
     29 Poly operator-(const Poly&,const Poly&);
     30 
     31 int rev[MAXN];
     32 
     33 int FindG(int);
     34 int NTTPre(int);
     35 int Sqrt(int,int);
     36 int Pow(int,int,int);
     37 int Log(int,int,int);
     38 int ExGCD(int,int,int&,int&);
     39 
     40 int k,m,x,n;
     41 int lg[MAXN];
     42 
     43 int main(){
     44     scanf("%d%d%d%d",&k,&m,&x,&n);
     45     Poly a(m-1);
     46     int g=FindG(m);
     47     for(int i=0,pw=1;i<m-1;i++,pw=pw*g%m)
     48         lg[pw]=i;
     49     for(int i=0;i<n;i++){
     50         int x;
     51         scanf("%d",&x);
     52         if(x)
     53             a[lg[x]]=1;
     54     }
     55     --m;
     56     Poly ans(a);
     57     --k;
     58     while(k>0){
     59         if(k&1){
     60             ans=a*ans;
     61             ans=ans+(ans>>m);
     62             ans.resize(m);
     63         }
     64         a=a*a;
     65         a=a+(a>>m);
     66         a.resize(m);
     67         k>>=1;
     68     }
     69     printf("%d
    ",ans[lg[x]]);
     70     return 0;
     71 }
     72 
     73 Poly operator<<(const Poly& a,int x){
     74     Poly ans(a.size()+x);
     75     for(size_t i=0;i<a.size();i++)
     76         ans[i+x]=a[i];
     77     return ans;
     78 }
     79 
     80 Poly operator>>(const Poly& a,int x){
     81     Poly ans(a.size()-x);
     82     for(size_t i=x;i<a.size();i++)
     83         ans[i-x]=a[i];
     84     return ans;
     85 }
     86 
     87 int FindG(int mod){
     88     for(int g=2;g<mod;g++){
     89         bool flag=true;
     90         for(int i=1,pw=g;i<mod-1;i++,pw=pw*g%mod){
     91             if(pw==1){
     92                 flag=false;
     93                 break;
     94             }
     95         }
     96         if(flag)
     97             return g;
     98     }
     99     return -1;
    100 }
    101 
    102 void Read(Poly& a){
    103     for(auto& i:a)
    104         scanf("%d",&i);
    105 }
    106 
    107 void Print(const Poly& a){
    108     for(auto i:a)
    109         printf("%d ",i);
    110     puts("");
    111 }
    112 
    113 Poly Pow(const Poly& a,int k){
    114     Poly log=Ln(a);
    115     for(auto& i:log)
    116         i=1ll*i*k%MOD;
    117     return Exp(log);
    118 }
    119 
    120 Poly Sqrt(Poly a){
    121     int len=a.size();
    122     if(len==1)
    123         return Poly(1,Sqrt(a[0],MOD));
    124     else{
    125         Poly b=a;
    126         b.resize((len+1)>>1);
    127         b=Sqrt(b);
    128         b.resize(len);
    129         Poly inv=Inverse(b);
    130         int bln=NTTPre(inv.size()+a.size());
    131         NTT(a,bln,DFT);
    132         NTT(inv,bln,DFT);
    133         for(int i=0;i<bln;i++)
    134             a[i]=1ll*a[i]*INV2%MOD*inv[i]%MOD;
    135         NTT(a,bln,IDFT);
    136         for(int i=0;i<len;i++)
    137             b[i]=(1ll*b[i]*INV2%MOD+a[i])%MOD;
    138         return b;
    139     }
    140 }
    141 
    142 Poly Exp(const Poly& a){
    143     size_t len=1;
    144     Poly ans(1,1),one(1,1);
    145     while(len<(a.size()<<1)){
    146         len<<=1;
    147         Poly b=a;
    148         b.resize(len);
    149         ans=ans*(one-Ln(ans)+b);
    150         ans.resize(len);
    151     }
    152     ans.resize(a.size());
    153     return ans;
    154 }
    155 
    156 Poly Ln(const Poly& a){
    157     Poly ans=Integral(Derivative(a)*Inverse(a));
    158     ans.resize(a.size());
    159     return ans;
    160 }
    161 
    162 Poly Integral(const Poly& a){
    163     int len=a.size();
    164     Poly ans(len+1);
    165     for(int i=1;i<len;i++)
    166         ans[i]=1ll*a[i-1]*Pow(i,MOD-2,MOD)%MOD;
    167     return ans;
    168 }
    169 
    170 Poly Derivative(const Poly& a){
    171     int len=a.size();
    172     Poly ans(len-1);
    173     for(int i=1;i<len;i++)
    174         ans[i-1]=1ll*a[i]*i%MOD;
    175     return ans;
    176 }
    177 
    178 Poly operator/(Poly a,Poly b){
    179     int n=a.size()-1,m=b.size()-1;
    180     Poly ans(1);
    181     if(n>=m){
    182         std::reverse(a.begin(),a.end());
    183         std::reverse(b.begin(),b.end());
    184         b.resize(n-m+1);
    185         ans=Inverse(b)*a;
    186         ans.resize(n-m+1);
    187         std::reverse(ans.begin(),ans.end());
    188     }
    189     return ans;
    190 }
    191 
    192 Poly operator%(Poly a,Poly b){
    193     int n=a.size()-1,m=b.size()-1;
    194     Poly ans;
    195     if(n<m)
    196         ans=a;
    197     else
    198         ans=a-(a/b)*b;
    199     ans.resize(m);
    200     return ans;
    201 }
    202 
    203 Poly operator*(Poly a,Poly b){
    204     int len=a.size()+b.size()-1;
    205     int bln=NTTPre(len);
    206     NTT(a,bln,DFT);
    207     NTT(b,bln,DFT);
    208     for(int i=0;i<bln;i++)
    209         a[i]=1ll*a[i]*b[i]%MOD;
    210     NTT(a,bln,IDFT);
    211     a.resize(len);
    212     return a;
    213 }
    214 
    215 Poly operator+(const Poly& a,const Poly& b){
    216     Poly ans(std::max(a.size(),b.size()));
    217     std::copy(a.begin(),a.end(),ans.begin());
    218     for(size_t i=0;i<b.size();i++)
    219         ans[i]=(ans[i]+b[i])%MOD;
    220     return ans;
    221 }
    222 
    223 Poly operator-(const Poly& a,const Poly& b){
    224     Poly ans(std::max(a.size(),b.size()));
    225     std::copy(a.begin(),a.end(),ans.begin());
    226     for(size_t i=0;i<b.size();i++)
    227         ans[i]=(ans[i]+MOD-b[i])%MOD;
    228     return ans;
    229 }
    230 
    231 Poly Inverse(Poly a){
    232     int len=a.size();
    233     if(len==1)
    234         return Poly(1,Pow(a[0],MOD-2,MOD));
    235     else{
    236         Poly b(a);
    237         b.resize((len+1)>>1);
    238         b=Inverse(b);
    239         int bln=NTTPre(b.size()*2+a.size());
    240         NTT(a,bln,DFT);
    241         NTT(b,bln,DFT);
    242         for(int i=0;i<bln;i++)
    243             b[i]=(2ll*b[i]%MOD-1ll*b[i]*b[i]%MOD*a[i]%MOD+MOD)%MOD;
    244         NTT(b,bln,IDFT);
    245         b.resize(len);
    246         return b;
    247     }
    248 }
    249 
    250 void NTT(Poly& a,int len,int opt){
    251     a.resize(len);
    252     for(int i=0;i<len;i++)
    253         if(rev[i]>i)
    254             std::swap(a[i],a[rev[i]]);
    255     for(int i=1;i<len;i<<=1){
    256         int step=i<<1;
    257         int wn=Pow(G,(PHI+opt*PHI/step)%PHI,MOD);
    258         for(int j=0;j<len;j+=step){
    259             int w=1;
    260             for(int k=0;k<i;k++,w=1ll*w*wn%MOD){
    261                 int x=a[j+k];
    262                 int y=1ll*a[j+k+i]*w%MOD;
    263                 a[j+k]=(x+y)%MOD;
    264                 a[j+k+i]=(x-y+MOD)%MOD;
    265             }
    266         }
    267     }
    268     if(opt==IDFT){
    269         int inv=Pow(len,MOD-2,MOD);
    270         for(int i=0;i<len;i++)
    271             a[i]=1ll*a[i]*inv%MOD;
    272     }
    273 }
    274 
    275 int NTTPre(int n){
    276     int bln=1,bct=0;
    277     while(bln<n){
    278         bln<<=1;
    279         ++bct;
    280     }
    281     for(int i=0;i<bln;i++)
    282         rev[i]=(rev[i>>1]>>1)|((i&1)<<(bct-1));
    283     return bln;
    284 }
    285 
    286 inline int Pow(int a,int n,int p){
    287     int ans=1;
    288     while(n>0){
    289         if(n&1)
    290             ans=1ll*a*ans%p;
    291         a=1ll*a*a%p;
    292         n>>=1;
    293     }
    294     return ans;
    295 }
    296 
    297 int ExGCD(int a,int b,int& x,int& y){
    298     if(b==0){
    299         x=1,y=0;
    300         return a;
    301     }
    302     else{
    303         int gcd=ExGCD(b,a%b,y,x);
    304         y-=x*(a/b);
    305         return gcd;
    306     }
    307 }
    308 
    309 inline int Sqrt(int a,int p){
    310     int s=Pow(G,Log(G,a,p)>>1,p);
    311     return std::min(s,MOD-s);
    312 }
    313 
    314 inline int Log(int a,int x,int p){
    315     int s=sqrt(p+0.5);
    316     int inv=Pow(Pow(a,s,p),p-2,p);
    317     std::unordered_map<int,int> m;
    318     m[1]=0;
    319     int pow=1;
    320     for(int i=1;i<s;i++){
    321         pow=1ll*a*pow%p;
    322         if(!m.count(pow))
    323             m[pow]=i;
    324     }
    325     for(int i=0;i<s;i++){
    326         if(m.count(x))
    327             return i*s+m[x];
    328         x=1ll*x*inv%MOD;
    329     }
    330     return -1;
    331 }
    BZOJ 3992

    日常图包

  • 相关阅读:
    SQL查询语句大全集锦
    SQL Union和SQL Union All用法
    SQL Server中替换函数STUFF、replace的使用
    oscache的使用(例子)
    SQL CURSOR 游标 存储过程
    折腾iPhone的生活——AirDrop的使用
    折腾iPhone的生活——通过设置使iPhone更省电
    折腾iPhone的生活——iPhone 5s 开启 assistive touch 后卡顿的问题
    vimium快捷键列表
    在MacOSX下使用Github管理Xcode代码
  • 原文地址:https://www.cnblogs.com/rvalue/p/10219943.html
Copyright © 2011-2022 走看看