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 2

Sample 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

[Submit][Status][Discuss]

好久没有调过这么痛苦了。。

首先有一个简单的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)的更多相关文章

  1. [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT)

    [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT) 题面 小C有一个集合S,里面的元素都是小于质数M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数 ...

  2. 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− ...

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

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

  4. BZOJ3992: [SDOI2015]序列统计(NTT 原根 生成函数)

    题意 题目链接 给出大小为\(S\)的集合,从中选出\(N\)个数,满足他们的乘积\(\% M = X\)的方案数 Sol 神仙题Orz 首先不难列出最裸的dp方程,设\(f[i][j]\)表示选了\ ...

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

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

  6. 【NTT】bzoj3992: [SDOI2015]序列统计

    板子题都差点不会了 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数 列,数列中的每个数都属于集合S.小C用这个生成器生 ...

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

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

  8. BZOJ3992: [SDOI2015]序列统计

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

  9. BZOJ3992 [SDOI2015]序列统计 【生成函数 + 多项式快速幂】

    题目 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数 列,数列中的每个数都属于集合S.小C用这个生成器生成了许多这样的数列.但是小C有一个问题 ...

随机推荐

  1. 【CodeForces】870 F. Paths

    [题目]F. Paths [题意]给定数字n,图上有编号为1~n的点,两点当且仅当gcd(u,v)≠1时有连边,定义d(u,v)为两点间最短距离(若不连通则为0),求Σd(u,v),1<=u&l ...

  2. 20155117王震宇 2006-2007-2 《Java程序设计》第一周学习总结

    20155117王震宇 2006-2007-2 <Java程序设计>第一周学习总结 教材学习内容总结 尽量简单的总结一下本周学习内容 尽量不要抄书,浪费时间 看懂就过,看不懂,学习有心得的 ...

  3. react-native关于ios的启动图标设置

    1.首先我们需要使用xcode打开项目,选择项目中的images.xcassets这个文件夹 2.点击AppIcon可以看到右边出现针对不同设备的图标尺寸 3.在左边空白处右击,选择Import... ...

  4. html 中的列表

    html 中列表可以分为 1.  无序列表(ul--li 的形式) 2.  有序列表(ol li的形式) 3.  定义列表(dl 的形式) 下面来看几种列表的具体内容: 1.无序列表. 无序列表的格式 ...

  5. Ice Cream Tower Gym - 101194D (贪心 + 二分 )

    题目链接 : https://cn.vjudge.net/problem/Gym-101194D 题目大意 : 给你n个冰激凌球,让你用这些冰激凌球去垒冰激凌,要求是下面的这一个必须是他上面一个的两倍 ...

  6. MYSQL三种安装方式--二进制包安装

    1. 把二进制包下载到/usr/local/src下 2. 如果是tar.gz包,则使用tar zxvf 进行解压 如果是tar包,则可以使用tar xvf 进行解压 3. $ mv mysql-5. ...

  7. 2017百度春招<有趣的排序>

    题目 度度熊有一个N个数的数组,他想将数组从小到大排好序,但是萌萌的度度熊只会下面这个操作:任取数组中的一个数然后将它放置在数组的最后一个位置.问最少操作多少次可以使得数组从小到大有序? #inclu ...

  8. int各种数据类型的表示范围

    计算方法:1.正数部分数部分:2^(字节数*8-1)-1 2.负数部分:-(2^(字节数*8-1)+1) unsign int:正数部分*2+1

  9. Quartz任务调度入门

    Quartz任务调度入门 了解Quartz体系结构Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器.任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的这些核心概念 ...

  10. Django 中form的用法

    form的主要作用:1.在html中生成表单框架,2.验证数据(实话实说,很简洁,但不实用,灵活性差) from django.db import models # Create your model ...