【题意】给定一个[0,m-1]范围内的数字集合S,从中选择n个数字(可重复)构成序列。给定x,求序列所有数字乘积%m后为x的序列方案数%1004535809。1<=n<=10^9,3<=m<=8000,m为素数,1<=x<=m-1。(个人认为题意修改错误)

【算法】NTT+生成函数+离散对数+快速幂

【题解】由Πai=x(%m),可得Σlog ai=log x(%(m-1)),其中log以m的原根g为底。

所以通过将集合S和x对m取离散对数,将乘积转化为和,从而方便生成函数运算。

定义,信息为数字和,选择项为数字个数。

对于1个数字,若转化后的S中存在x,则f(x)=1,否则f(x)=0。

那么ans=f^n(x),使用以NTT为乘法运算的快速幂即可。

注意:

1.每次NTT后,将>=m-1的部分叠加到%(m-1)的位置。

2.每次dft会改变原数组,所以要提前复制一份。

3.若集合S中有数字0,无视。

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=,MOD=;
int a[maxn],b[maxn],tot,n,X,p,K,logs[maxn],f[maxn],ans[maxn],c[maxn];
void exgcd(int a,int b,int &x,int &y){
if(!b){x=;y=;}
else{exgcd(b,a%b,y,x);y-=x*(a/b);}
}
int inv(int a){int x,y;exgcd(a,MOD,x,y);return (x%MOD+MOD)%MOD;}
int power(int x,int k,int p){
int ans=;
while(k){
if(k&)ans=1ll*ans*x%p;
x=1ll*x*x%p;
k>>=;
}
return ans;
}
namespace ntt{
int o[maxn],oi[maxn];
void init(int n){
int g=,x=power(g,(MOD-)/n,MOD);
for(int i=;i<n;i++){
o[i]=(i==?:1ll*o[i-]*x%MOD);
oi[i]=inv(o[i]);
}
}
void transform(int *a,int n,int *o){
int k=;
while((<<k)<n)k++;
for(int i=;i<n;i++){
int t=;
for(int j=;j<k;j++)if((<<j)&i)t|=(<<(k-j-));
if(i<t)swap(a[i],a[t]);
}
for(int l=;l<=n;l*=){
int m=l>>;
for(int *p=a;p!=a+n;p+=l){
for(int i=;i<m;i++){
int t=1ll*o[n/l*i]*p[i+m]%MOD;
p[i+m]=(p[i]-t+MOD)%MOD;
p[i]=(p[i]+t)%MOD;
}
}
}
}
void dft(int *a,int n){transform(a,n,o);}
void idft(int *a,int n){
transform(a,n,oi);
int nn=inv(n);
for(int i=;i<n;i++)a[i]=1ll*a[i]*nn%MOD;
}
void multply(int *a,int *b,int n){
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;
idft(a,n);
for(int i=p-;i<n;i++)if(a[i])a[i%(p-)]=(a[i%(p-)]+a[i])%MOD,a[i]=;
}
}
int find(int p){
int sq=(int)(sqrt(p)+0.5),P=p-;
for(int i=;i<=sq;i++)if(P!=){
if(P%i==){
b[++tot]=i;
while(P%i==)P/=i;
}
}
if(P!=)b[++tot]=P;
for(int i=;i<=p;i++){
bool ok=;
for(int j=;j<=tot;j++)if(power(i,(p-)/b[j],p)==){ok=;break;}
if(ok)return i;
}
return ;
}
void pre_log(){
int g=find(p),x=;
for(int i=;i<p-;i++){
logs[x]=i;
x=1ll*x*g%p;
}
}
void POWER(){
int N=;
while(N<p+p-)N*=;
ntt::init(N);
ans[]=;
while(K){
if(K&)ntt::multply(ans,f,N);
ntt::multply(f,f,N);
K>>=;
}
}
int main(){
scanf("%d%d%d%d",&K,&p,&X,&n);
pre_log();
int x;
for(int i=;i<=n;i++){
scanf("%d",&x);
if(!x)continue;
f[logs[x]]=;
}
POWER();
printf("%d",ans[logs[X]]);
return ;
}

【BZOJ】3992: [SDOI2015]序列统计 NTT+生成函数的更多相关文章

  1. BZOJ 3992: [SDOI2015]序列统计 NTT+快速幂

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1155  Solved: 532[Submit][Statu ...

  2. bzoj 3992 [SDOI2015]序列统计——NTT(循环卷积&&快速幂)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 有转移次数.模M余数.方案数三个值,一看就是系数的地方放一个值.指数的地方放一个值.做 ...

  3. bzoj 3992 [SDOI2015] 序列统计 —— NTT (循环卷积+快速幂)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 (学习NTT:https://riteme.github.io/blog/2016-8 ...

  4. bzoj 3992: [SDOI2015]序列统计 NTT+原根

    今天开始学习丧心病狂的多项式qaq......    . code: #include <bits/stdc++.h> #define ll long long #define setIO ...

  5. BZOJ 3992: [SDOI2015]序列统计 [快速数论变换 生成函数 离散对数]

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1017  Solved: 466[Submit][Statu ...

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

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

  7. [BZOJ 3992][SDOI2015]序列统计

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 2275  Solved: 1090[Submit][Stat ...

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

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

  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. 1st 构建之法读后感

    构建之法读后感 由于时间和书的篇幅所限,所以我没能真正通读全书,只通过网上的介绍和书内前言及目录,大概了解了构建之法是一本怎样的一本书. 这本书是由具有长达20年一线软件开发经验的邹欣老师所撰写,他以 ...

  2. 发布vue插件到npm上

    总体分为2个步骤 一,先写好插件 二,发布到npm上面 一,写vue插件 vue有一个开放的方法install,在vue插件需要写在这个方法里面,在vue官网,里面说的很清楚,这个方法里面可以是全局方 ...

  3. js & right click menu & 鼠标滑词

    js & right click menu & 鼠标滑词 // 鼠标滑词 mouseSlipGetWords() { const getSelectionText = () => ...

  4. [计算机网络-数据链路层] CSMA、CSMA/CA、CSMA/CD详解

    1.CSMA(载波侦听多路访问协议) CSMA 当其他节点检测到信道被占用时不发送数据.但是当数据发送完后其他节点同时检测到信道为空闲,之后又在同一时刻发送数据,可能再次产生冲突. 2.CSMA/CD ...

  5. [LeetCode] Search in Rotated Array

    Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...

  6. Android性能测试工具APT

    APT源码地址:https://code.csdn.net/Tencent/apt APT,Android Performance Testing Tools,适用于开发自测和定位性能瓶颈,帮助测试人 ...

  7. BZOJ4883 棋盘上的守卫(环套树+最小生成树)

    容易想到网络流之类的东西,虽然范围看起来不太可做,不过这提供了一种想法,即将行列分别看做点.那么我们需要找一种连n+m条边的方案,使得可以从每条边中选一个点以覆盖所有点.显然每个点至少要连一条边.于是 ...

  8. P2812 校园网络【[USACO]Network of Schools加强版】

    题目背景 浙江省的几所OI强校的神犇发明了一种人工智能,可以AC任何题目,所以他们决定建立一个网络来共享这个软件.但是由于他们脑力劳动过多导致全身无力身体被♂掏♂空,他们来找你帮助他们. 题目描述 共 ...

  9. 【刷题】洛谷 P3808 【模板】AC自动机(简单版)

    题目背景 这是一道简单的AC自动机模板题. 用于检测正确性以及算法常数. 为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交. 管理员提示:本题数据内有重复的单词,且重复单词应该计算多次, ...

  10. 【CF528D】Fuzzy Search(FFT)

    [CF528D]Fuzzy Search(FFT) 题面 给定两个只含有\(A,T,G,C\)的\(DNA\)序列 定义一个字符\(c\)可以被匹配为:它对齐的字符,在距离\(K\)以内,存在一个字符 ...