[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有一个问题 ...
随机推荐
- 【BZOJ】2099: [Usaco2010 Dec]Letter 恐吓信
[题意]给定长度为n和m的两个字符串S和T,要求在字符串S中取出若干段拼成T(可重复取),求最小段数,n,m<=50000. [算法]后缀自动机 || 后缀数组 [题解]对串S建SAM,然后在上 ...
- onblur & onchange
本文地址:http://www.cnblogs.com/veinyin/p/7606914.html 两者均可用于验证是否输入数据 onblur : 表示不再是焦点,是 onfocus 的相反事件, ...
- python3学习笔记.1.初体验
最近工作烦得很 就想找点儿别的事情来做,于是想到了学学python. 因为是vs2017,所以就在里面安装了. 第一个程序肯定是Hello World了. 新建一个python应用程序 代码只有一行 ...
- F - Debate CodeForces - 1070F 思维
题目链接:https://vjudge.net/problem/CodeForces-1070F 具体思路:首先把所有的00放进去,然后对于10 和01 的取两个数目最小值t,排完序后将前t个加起来, ...
- wget下载整个网站或特定目录
下载整个网站或特定目录 wget -c -k -r -np -p http://www.yoursite.com/path -c, –continue 断点下载 -k, –convert-links ...
- 64_n1
NFStest-2.1.5-0.fc26.noarch.rpm 16-Feb-2017 16:19 544018 NLopt-2.4.2-11.fc26.i686.rpm 13-Feb-2017 23 ...
- ThoughtWorks代码挑战——FizzBuzzWhizz游戏 通用高速版(C/C++ & C#)
最早看到这个题目是从@ 程序媛想事儿(Alexia) 的 最难面试的IT公司之ThoughtWorks代码挑战——FizzBuzzWhizz游戏 开始的,然后这几天陆陆续续有N个小伙伴发表了自己的文章 ...
- StringBuilder基本用法
//StringBuilder用法 public class StringBuilderTest { public static void main(String[] args) { StringBu ...
- socket-----爬虫&&文件传输
最近想着写几个小demo 写了一个爬虫,用的是C++,基本思想就是一层一层的找类似深搜吧,抓取的页面是www.cnblogs.com,从localhost发送request请求,给www.cnblog ...
- “全排列”问题系列(一)[LeetCode] - 用交换元素法生成全排列及其应用,例题: Permutations I 和 II, N-Queens I 和 II,数独问题
转:http://www.cnblogs.com/felixfang/p/3705754.html 一.开篇 Permutation,排列问题.这篇博文以几道LeetCode的题目和引用剑指offer ...