3992: [SDOI2015]序列统计

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 1155  Solved: 532
[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中的所有元素。

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中元素不重复
 

Source

Round 1 感谢yts1999上传

想法:

设a[i]表示数字i是否属于集合S,C[i]表示数列之积%M=i的方案数。  当n=2时:
  c[(i*j)%M]=∑a[i]*a[j]
  令A[i]=a[g^i],C[i]=c[g^i]//∵g为M原根,遍历0~M-1,而将数组映射到另一个数组,并不影响答案,只要改变运算规则。
  由 c[g^(i+j)%M]=∑a[g^i]*a[g^j] 得到:
  C[(i+j)%(M-1)]=∑A[i]*A[j]//费马小定理:g^(M-1)

  ∵j+i≤m*2
  ∴每次FFT后将后面的累加到前面来就行了。
  当n=y时,C=A^y,找到g^j=x,输出C[j] 于是NTT+快速幂O(nlog^2n)
 #include<cstdio>
#define ll long long
const int MP(),lem(),g();
int n,m,x,size,gm;
int a[lem+],num,p[],tp;
struct data{int a[lem+];}A,C,B;
int power(int a,int b,int MP)
{
ll t=,y=a;b+=b<?MP-:;
for(;b;b>>=,y=(y*y)%MP)if(b&)t=(t*y)%MP;
return (int)t;
}
bool check(int y)
{
for(int j=;j<=tp;j++)
if(power(y,(m-)/p[j],m)==)return false;
return true;
}
void Get_g(int x)
{
if(!(x&))
{
p[++tp]=;
while(!(x&))x>>=;
}
for(int i=;i*i<=x;i+=)
{
if(x%i==)
{
p[++tp]=i;
while(x%i==)x/=i;
}
}
if(x>)p[++tp]=x;
for(int i=;i<=m-;i++)
if(check(i)){gm=i;break;}
}
int R[lem+],w[lem+],wn,l,il,h;
void deal()
{
l=;w[]=;
while(l<=m+m)l<<=,h++;
for(int i=;i<l;i++)R[i]=(R[i>>]>>|(i&)<<(h-));
il=power(l,MP-,MP);
}
void swap(int &a,int &b){if(a==b)return;a^=b;b^=a;a^=b;}
void NTT(int *a,int l,int ty)
{
for(int i=;i<l;i++)if(i<R[i])swap(a[i],a[R[i]]);
for(int leng=;leng<=l;leng<<=)
{
int M=leng>>;
wn=power(g,ty*(MP-)/leng,MP);
for(int i=;i<M;i++)w[i]=(1ll*w[i-]*wn)%MP;
for(int i=;i<l;i+=leng)
{
for(int j=;j<M;j++)
{
int x=a[i+j],y=(1ll*w[j]*a[i+j+M])%MP;
a[i+j]=x+y;a[i+j+M]=x-y;
a[i+j]-=a[i+j]>=MP?MP:;
a[i+j+M]+=a[i+j+M]<?MP:;
}
}
}
if(ty==-)
for(int i=;i<l;i++)a[i]=(1ll*a[i]*il)%MP;
}
void three(data &A,data &B)
{
NTT(A.a,l,);NTT(B.a,l,);
for(int i=;i<l;i++)B.a[i]=(1ll*B.a[i]*A.a[i])%MP;
NTT(B.a,l,-);
for(int i=m-;i<l;i++)B.a[i%(m-)]=(B.a[i%(m-)]+B.a[i])%MP,B.a[i]=;
}
void run()
{
C.a[]=;
while(n)
{
if(n&)
{
B=A;
three(B,C);
}
B=A;
three(B,A);
n>>=;
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&x,&size);
for(int i=;i<=size;i++){scanf("%d",&num);a[num]=;}
Get_g(m-);deal();
for(int i=,j=;i<m-;i++,j=(j*gm)%m)
{
A.a[i]=a[j];
if(j==x)num=i;
}
run();
printf("%d",C.a[num]);
return ;
}

BZOJ 3992: [SDOI2015]序列统计 NTT+快速幂的更多相关文章

  1. bzoj 3992 [SDOI2015]序列统计——NTT(循环卷积&&快速幂)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 有转移次数.模M余数.方案数三个值,一看就是系数的地方放一个值.指数的地方放一个值.做 ...

  2. bzoj 3992 [SDOI2015] 序列统计 —— NTT (循环卷积+快速幂)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 (学习NTT:https://riteme.github.io/blog/2016-8 ...

  3. bzoj 3992: [SDOI2015]序列统计 NTT+原根

    今天开始学习丧心病狂的多项式qaq......    . code: #include <bits/stdc++.h> #define ll long long #define setIO ...

  4. BZOJ 3992: [SDOI2015]序列统计 快速幂+NTT(离散对数下)

    3992: [SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S ...

  5. BZOJ 3992: [SDOI2015]序列统计 [快速数论变换 生成函数 离散对数]

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1017  Solved: 466[Submit][Statu ...

  6. [BZOJ 3992][SDOI2015]序列统计

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 2275  Solved: 1090[Submit][Stat ...

  7. bzoj 3992: [SDOI2015]序列统计【原根+生成函数+NTT+快速幂】

    还是没有理解透原根--题目提示其实挺明显的,M是质数,然后1<=x<=M-1 这种计数就容易想到生成函数,但是生成函数是加法,而这里是乘法,所以要想办法变成加法 首先因为0和任何数乘都是0 ...

  8. 【BZOJ】3992: [SDOI2015]序列统计 NTT+生成函数

    [题意]给定一个[0,m-1]范围内的数字集合S,从中选择n个数字(可重复)构成序列.给定x,求序列所有数字乘积%m后为x的序列方案数%1004535809.1<=n<=10^9,3< ...

  9. BZOJ.3992.[SDOI2015]序列统计(DP NTT 原根)

    题目链接 \(Description\) 给定\(n,m,x\)和集合\(S\).求\(\prod_{i=1}^na_i\equiv x\ (mod\ m)\)的方案数.其中\(a_i\in S\). ...

随机推荐

  1. switch()出现警告warning:enumeration value ‘xxx’ not handled in switch

    enumeration value ... not handled in switch 如果在switch中使用使用枚举类型,如:switch(枚举类型) 枚举类型的个数没有全部列出,就会报这个警告

  2. IE11浏览器中的My97日历控件刷新后无法打开问题解决办法

    IE11浏览器中的My97日历控件刷新后无法打开问题解决办法   IE11浏览器中的My97日历控件刷新后无法打开问题解决办法:(谷歌浏览器下正常.IE11失效) 解决办法:1:找到WdatePick ...

  3. lightoj1010【规律】

    思路: 根据案例的规律其实已经猜的差不多了,answer=n*m/2; 有一条边是1的情况,也很好判断,answer=n*m; 就是有一条边是2的时候比较隐秘:是连续2*2一块可以填,然后2*2不填, ...

  4. JS 上拉加载

    $(document).ready( function(){ $contentLoadTriggered = false; $("#mainDiv").scroll(functio ...

  5. 洛谷P3405 [USACO16DEC]Cities and States省市

    P3405 [USACO16DEC]Cities and States省市 题目描述 To keep his cows intellectually stimulated, Farmer John h ...

  6. python2与python3 版本区别

    目录 编码 输入输出 中文 除法 长整形 内置函数map xrange init reduce 字符串类型 dict字典 经典类 新式类 未完待补充 编码 python2默认编码器为ascii码(只支 ...

  7. 关于HTML5用SVG画图

    SVG在HTML5中的应用 SVG(Scalable Vector Graphics)是用来绘制矢量图的HTML5标签.只要定义好XML属性就能够获得与其一致的图像元素. 使用SVG之前先将标签加入到 ...

  8. JavaScript进阶 - 第5章 小程序,大作用(函数)

    5-1什么是函数 函数的作用,可以写一次代码,然后反复地重用这个代码. 如:我们要完成多组数和的功能. var sum;   sum = 3+2; alert(sum);   sum=7+8 ; al ...

  9. 2017 ACM/ICPC Asia Regional Shenyang Online cable cable cable

    Problem Description Connecting the display screen and signal sources which produce different color s ...

  10. Netty(1-2)Discard Client

    一.DiscardClientHandler import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelFuture; import ...