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

    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中的所有元素。

    Output

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

    Sample Input

    4 3 1 2
    1 2

    Sample Output

    8

    HINT

    【样例说明】
    可以生成的满足要求的不同的数列有(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)。
    【数据规模和约定】
    对于10%的数据,1<=N<=1000;
    对于30%的数据,3<=M<=100;
    对于60%的数据,3<=M<=800;
    对于全部的数据,1<=N<=109,3<=M<=8000,M为质数,1<=x<=M-1,输入数据保证集合S中元素不重复
    首先对于模数m的原根G,每个i=1~m-1,都有唯一的j属于[0,m-2],使得$G^{j}=i$

    求原根可以先找出p-1的所有质因数,然后从2开始枚举,如果对任意的p-1的质因数p[i],x的(p-1)/p[i]次幂模p都不等于1,则x是p的一个原根

    原根一般比较小,可以暴力找

    那么乘法就转化为加法,以下所说的数的都是离散对数,也就是每个j对应的i
    对于x,如果i+j=x
    那么x的方案数f[x]显然要加上f[i]*f[j]
    这显然是一个多项式形式,也就是多项式乘法
    因为求的是小于m-1的方案数,所以每次相乘要把大于m-1的方案合并
    原题相当于n个多项式相乘,求某一项的系数
    因为n很大,而且因为合并答案,所以长度不会超过2*m-2
    用快速幂套NTT就可以了
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 using namespace std;
      7 typedef long long lol;
      8 lol MOD=1004535809;
      9 lol X,S,G,p[10001],a[80001],b[80001],R[80001];
     10 int pri[100001];
     11 lol qpow(lol x,lol y,lol Mod)
     12 {
     13   lol res=1;
     14   while (y)
     15     {
     16       if (y&1) res=res*x%Mod;
     17       x=x*x%Mod;
     18       y>>=1;
     19     }
     20   return res;
     21 }
     22 lol getG(lol m)
     23 {
     24   lol i,j;
     25   lol x=m-1,tot=0,flag;
     26   for (i=2;i<=sqrt(m-1);i++)
     27     if (x%i==0)
     28       {
     29     pri[++tot]=i;
     30     while (x%i==0) x/=i;
     31       }
     32   if (x!=1)
     33     {
     34       pri[++tot]=x;
     35     }
     36   for (i=2;;i++)
     37     {
     38       flag=1;
     39       for (j=1;j<=tot;j++)
     40     if (qpow(i,(m-1)/pri[j],m)==1)
     41       {
     42         flag=0;
     43         break;
     44       }
     45       if (flag)
     46     return i;
     47     }
     48 }
     49 void NTT(lol *A,int len,int o)
     50 {lol i,j,k;
     51   for (i=0;i<len;i++)
     52     if (i<R[i]) swap(A[i],A[R[i]]);
     53   for (i=1;i<len;i<<=1)
     54     {
     55       lol wn=qpow(3,(MOD-1)/(i<<1),MOD),x,y;
     56       if (o==-1) wn=qpow(wn,MOD-2,MOD);
     57       for (j=0;j<len;j+=(i<<1))
     58     {
     59       lol w=1;
     60       for (k=0;k<i;k++,w=w*wn%MOD)
     61         {
     62           x=A[j+k];y=w*A[j+k+i]%MOD;
     63           A[j+k]=(x+y)%MOD;
     64           A[j+k+i]=(x-y+MOD)%MOD;
     65         }
     66     }
     67     }
     68   if (o==-1)
     69     {
     70       lol tmp=qpow(len,MOD-2,MOD);
     71       for (i=0;i<len;i++)
     72     A[i]=A[i]*tmp%MOD;
     73     }
     74 }
     75 int main()
     76 {lol i,x,len,lg=0,n,m;
     77   cin>>n>>m>>X>>S;
     78   G=getG(m);
     79   lol tmp=1;
     80   for (i=0;i<m-1;i++)
     81     {
     82       p[tmp]=i;
     83       tmp=(tmp*G)%m;
     84     }
     85   for (i=1;i<=S;i++)
     86     {
     87       scanf("%lld",&x);
     88       if (x) a[p[x]]++;
     89     }
     90   len=1;
     91   while (len<=2*m-2) len*=2,lg++;
     92   for (i=0;i<len;i++)
     93     R[i]=(R[i>>1]>>1)|((i&1)<<(lg-1));
     94   b[0]=1;
     95   while (n)
     96     {
     97       if (n&1)
     98     {
     99       NTT(a,len,1);
    100       NTT(b,len,1);
    101       for (i=0;i<len;i++)
    102           b[i]=b[i]*a[i]%MOD;
    103       NTT(b,len,-1);
    104       NTT(a,len,-1);
    105       for (i=m-1;i<len;i++)
    106         b[i%(m-1)]+=b[i],b[i%(m-1)]%=MOD,b[i]=0; 
    107     }
    108       NTT(a,len,1);
    109       for (i=0;i<len;i++)
    110     a[i]=a[i]*a[i]%MOD;
    111       NTT(a,len,-1);
    112       for (i=m-1;i<len;i++)
    113     a[i%(m-1)]+=a[i],a[i%(m-1)]%=MOD,a[i]=0;
    114       n>>=1;
    115     }
    116   printf("%lld
    ",b[p[X]]);
    117 }
  • 相关阅读:
    [NOI2003],[AHOI2006]文本编辑器
    luogu P5151 HKE与他的小朋友
    [NOI2005]维护数列
    [HNOI2012]永无乡
    luogu P4146 序列终结者
    [SCOI2016]美味
    UVA1451 Average
    [JSOI2007]字符加密
    luogu P3809 【模板】后缀排序
    CentOS 7系统启动后怎么从命令行模式切换到图形界面模式
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8416170.html
Copyright © 2011-2022 走看看