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. 【问题总结】万万没想到,竟然栽在了List手里

    说明 昨天同事开发的时候遇到了一个奇怪的问题. 使用Guava做缓存,往里面存一个List,为了方便描述,称它为列表A,在另一个地方取出来,再跟列表B中的元素进行差集处理,简单来说,就像是下面这样: ...

  2. 浅析Jupyter Notebook

    一 概述 Jupyter Notebook是以web交互式的编程接口,是IPython notebook的升级版本.主要是针对python,另外支持运行 40 多种编程语言.Jupyter可以在个人机 ...

  3. PHP之递归函数

    https://www.cnsecer.com/4146.html http://www.jb51.net/article/71424.htm //一列数字的规则如下:1,1,2,3,5,8,13,2 ...

  4. 洛谷P3431 [POI2005]AUT-The Bus

    P3431 [POI2005]AUT-The Bus 题目描述 The streets of Byte City form a regular, chessboardlike network - th ...

  5. MySQL变更之:Online DDL 和 PT-OSC 该选谁?

    参考: http://www.fromdual.ch/online-ddl_vs_pt-online-schema-change 在MySQL 5.6版本以前,最昂贵的数据库操作之一就是执行数据定义语 ...

  6. 基于react+如何搭建一个完整的前端框架(1)

      1.使用 create-react-app 快速构建 React 开发环境 create-react-app 是来自于 Facebook,通过该命令我们无需配置就能快速构建 React 开发环境. ...

  7. zabbix agent 配置

    http://blog.csdn.net/z644041867/article/details/76618644 https://www.cnblogs.com/miclesvic/p/6144924 ...

  8. SqlDbx连接oracle

    解压SqlDbx.zip,将SqlDbx放到C:盘根目录 1.Path里面增加:C:\SqlDbx  Path是为了找tnsnames.ora 2.增加系统变量:ORACLE_HOME,路径:C:\S ...

  9. Echarts的重点

    官网中,主要看文档的”教程“和”配置项手册“这两部分 1 下载 引入js 页面放一个容器,一定要设宽高 创建对象:var myChart = echarts.init(document.getElem ...

  10. Java基础语法(Eclipse)

    Java基础语法 今日内容介绍 u Eclipse开发工具 u 超市库存管理系统 第1章 Eclipse开发工具 Eclipse是功能强大Java集成开发工具.它可以极大地提升我们的开发效率.可以自动 ...