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. ajax方法data参数用法的总结

    源文件分析: data的传递格式有两种:一是url字符串格式:一种是Json格式,格式分别如上 区别是:当传递的参数中包含 特殊字符如:&时,服务器解析这个参数时就会出错,而必须用encode ...

  2. Struts2+JQuery+Json登陆实例

    Struts2+JQuery+Json登陆实例 博客分类: Struts2   在搭建之前.. 首先,需要准备struts2.0框架的5个核心包, 以及jsonplugin-0.32.jar 以及js ...

  3. Acdream手速赛7

    蛋疼啊,本次只做出了一道题目...渣爆了... 妈蛋,,卡题之夜..比赛结果是1道题,比赛完哗啦哗啦出4道题.. A acdream1191 Dragon Maze 题意: 给一个迷宫,给出入口坐标和 ...

  4. 第一课、OpenGL绘制直线等等

    第一课.OpenGL绘制直线等等 分类: [开发技术]OpenGL 2012-01-18 14:59 5217人阅读 评论(0) 收藏 举报 buffer图形c // //  main.c //  o ...

  5. Python服务Debian打包新思路

    此文已由作者张耕源授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Debian 打包一直是比较冷僻的技术,大部分同学都不会接触到它. 但是我们 Debian 服务器上安装的各 ...

  6. 剑指Offer的学习笔记(C#篇)-- 跳台阶

    题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). 一 . 解题思路. 由题目可知,青蛙一次可以跳一阶或者两阶.假设台阶为 ...

  7. 洛谷 P1070 道路游戏(noip 2009 普及组 第四题)

    题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有 nn个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将这 nn个机器人工厂编 ...

  8. PAT甲级——1105 Spiral Matrix (螺旋矩阵)

    此文同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/90484058 1105 Spiral Matrix (25 分) ...

  9. render函数和redirect函数的区别+反向解析

    render函数和redirect函数的区别+反向解析 1.视图函数:一定是要包含两个对象的(render源码里面有HttpResponse对象)   request对象:----->所有的请求 ...

  10. A-坐飞机

    链接:https://ac.nowcoder.com/acm/contest/892/A 题意: 鸡尾酒要去很多很多地方玩,于是他一次买了 n 张机票,初始鸡尾酒在第一个城市,对于任意的i(1≤i≤n ...