[BZOJ3992][SDOI2015]序列统计(DP+原根+NTT)
3992: [SDOI2015]序列统计
Time Limit: 30 Sec Memory Limit: 128 MB
Submit: 1888 Solved: 898
[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 2Sample 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)HINT
Source
好久没有调过这么痛苦了。。
首先有一个简单的DP方程:$dp[i+j][(x*y)\%p]+=dp[i][x]*dp[j][y]$,dp[i][j]表示前i个数凑成余数为j的方案数。
$n^2$转移很简单,然后可以矩阵优化,但M的范围仍然过不了。
这时候就要敢往FFT方面去想。
现在这个方程之所以不能用FFT的原因在于x,y转移到的不是x+y而是x*y%mod,我们可以想到,乘法运算在作为指数的时候就是加法,又发现M是质数,于是我们考虑用原根的次幂替代S中的每个数。
设$g^{x'} \equiv x (mod\ p)$,$g^{y'} \equiv y (mod\ p)$,这样方程就变为$dp[i+j][(x'+y')\% \phi(p)]+=dp[i][x']*dp[j][y']$,这个就是标准的循环卷积了。
注意循环卷积次数界要再放大一倍!!还有S中要忽略0!!两个问题调到崩溃。
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const int N=,mod=,G=;
int k,p,x,n,s,g,inv,cnt[N],f[N],pw[N],ind[N],rev[N],c[N]; int ksm(int a,int b,int p){
int res;
for (res=; b; a=(1ll*a*a)%p,b>>=)
if (b & ) res=(1ll*res*a)%p;
return res;
} bool chk(){
for (int i=; i*i<=p; i++) if ((p-)%i== && ksm(g,(p-)/i,p)==) return ;
return ;
} void getroot(){
if (p==) g=; else for (g=; !chk(); g++);
ind[]=; pw[]=;
for (int i=; i<p-; i++) pw[i]=pw[i-]*g%p,ind[pw[i]]=i;
} namespace NTT{
int n,L,rev[N];
void init(int m){
n=; L=;
for (; n<=m; n<<=) L++;
n<<=; L++; inv=ksm(n,mod-,mod);
for (int i=; i<n; i++) rev[i]=(rev[i>>]>>)|((i&)<<(L-));
}
void DFT(int a[],int n,int f){
for (int i=; i<n; i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
for (int i=; i<n; i<<=){
int wn=ksm(G,(f==) ? (mod-)/(i<<) : (mod-)-(mod-)/(i<<),mod);
for (int p=i<<,j=; j<n; j+=p){
int w=;
for (int k=; k<i; k++,w=1ll*w*wn%mod){
int x=a[j+k],y=1ll*w*a[i+j+k]%mod;
a[j+k]=(x+y)%mod; a[i+j+k]=(x-y+mod)%mod;
}
}
}
if (f==) return;
for (int i=; i<n; i++) a[i]=1ll*a[i]*inv%mod;
}
void mul(int a[],int b[]){
for (int i=; i<n; i++) c[i]=b[i];
DFT(a,n,); DFT(c,n,);
for (int i=; i<n; i++) a[i]=1ll*a[i]*c[i]%mod;
DFT(a,n,-);
for (int i=n-; i>=p-; i--) a[i-p+]=(a[i-p+]+a[i])%mod,a[i]=;
}
}; int main(){
freopen("bzoj3992.in","r",stdin);
freopen("bzoj3992.out","w",stdout);
scanf("%d%d%d%d",&k,&p,&x,&n); getroot(); NTT::init(p);
rep(i,,n) { scanf("%d",&s); if (s) cnt[ind[s]]++; }
for (f[]=; k; k>>=,NTT::mul(cnt,cnt)) if (k & ) NTT::mul(f,cnt);
printf("%d\n",f[ind[x]]);
return ;
}
[BZOJ3992][SDOI2015]序列统计(DP+原根+NTT)的更多相关文章
- [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT)
[BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT) 题面 小C有一个集合S,里面的元素都是小于质数M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数 ...
- 2018.12.31 bzoj3992: [SDOI2015]序列统计(生成函数+ntt+快速幂)
传送门 生成函数简单题. 题意:给出一个集合A={a1,a2,...as}A=\{a_1,a_2,...a_s\}A={a1,a2,...as},所有数都在[0,m−1][0,m-1][0,m− ...
- BZOJ 3992: [SDOI2015]序列统计 快速幂+NTT(离散对数下)
3992: [SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S ...
- BZOJ3992: [SDOI2015]序列统计(NTT 原根 生成函数)
题意 题目链接 给出大小为\(S\)的集合,从中选出\(N\)个数,满足他们的乘积\(\% M = X\)的方案数 Sol 神仙题Orz 首先不难列出最裸的dp方程,设\(f[i][j]\)表示选了\ ...
- BZOJ.3992.[SDOI2015]序列统计(DP NTT 原根)
题目链接 \(Description\) 给定\(n,m,x\)和集合\(S\).求\(\prod_{i=1}^na_i\equiv x\ (mod\ m)\)的方案数.其中\(a_i\in S\). ...
- 【NTT】bzoj3992: [SDOI2015]序列统计
板子题都差点不会了 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数 列,数列中的每个数都属于集合S.小C用这个生成器生 ...
- bzoj 3992: [SDOI2015]序列统计【原根+生成函数+NTT+快速幂】
还是没有理解透原根--题目提示其实挺明显的,M是质数,然后1<=x<=M-1 这种计数就容易想到生成函数,但是生成函数是加法,而这里是乘法,所以要想办法变成加法 首先因为0和任何数乘都是0 ...
- BZOJ3992: [SDOI2015]序列统计
Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S. 小C用这个生成器生成了许多这样的数列. ...
- BZOJ3992 [SDOI2015]序列统计 【生成函数 + 多项式快速幂】
题目 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数 列,数列中的每个数都属于集合S.小C用这个生成器生成了许多这样的数列.但是小C有一个问题 ...
随机推荐
- react 项目遇到的警告集锦
1. 2.
- CodeForces 990C
Description A bracket sequence is a string containing only characters "(" and ")" ...
- http介绍
1.http特点: 1>简单快捷: 2>灵活: 3>支持客户端.服务器结构: 4>无连接----无连接的含义是限制每次连接只处理一个请求: 5>无状态----无状态是指协 ...
- 自动化运维工具SaltStack详细部署【转】
==========================================================================================一.基础介绍==== ...
- glom模块的使用(二)
上次我们说到golm的简单应用这次我们继续带结构化数据的其他操作进行学习. Literal 用法:class glom.Literal(value) 这个方法的功能主要是添加自定义的键值. 例如: f ...
- 45.Jump Game II---贪心---2018大疆笔试题
题目链接 题目大意:与55题类似,只是这里要求出跳数. 法一(借鉴):贪心.cur表示当前能到达的最远距离,pre表示上一次能到达的最远距离,每到一个位置更新一次最远距离cur,如果当前位置超过了上一 ...
- [转载]Firefox插件(plugins)开发实用指南
转自: http://huandu.me/2010/02/11/595/ Firefox插件可实现强大功能,但其中麻烦事情不少.写这个实用指南首先是为了方便自己记忆,免得以后再次栽倒一些坑里面,如果能 ...
- 集合框架之Set学习
前言: 1.何为框架:可以理解为一个基础结构,在基础结构上进行进一步开发会变得很方便. 2.三种集合类型:集合(Set) :元素无序不可重复: 列表(List) :元素有序可重复: 映 ...
- [ python ] 正则表达式及re模块
正则表达式 正则表达式描述: 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个‘规则字符串’,这个‘规则字符串’用来 表达对字符串的一种过滤 ...
- 强大的PHP一句话后门
强悍的PHP一句话后门 这类后门让网站.服务器管理员很是头疼,经常要换着方法进行各种检测,而很多新出现的编写技术,用普通的检测方法是没法发现并处理的. 今天我们细数一些有意思的PHP一句话木马. 1 ...