思路

首先有个挺显然的DP

\[dp[i][(j*k)\%m]+=dp[i-1][j]\times dp[i-1][k]
\]

想办法优化这个DP

这个dp也可以写成这样

\[dp[i][j]=\sum_{p*q=j}dp[i-1][p]\times dp[i-1][q]
\]

看着一副卷积的样子

但是是乘法,可以考虑转化乘法为加法,有两种方式,取ln或者原根

注意到m是质数,所以取原根,每层之间的转移就变成卷积了

但是这题的卷积下标是模m的,所以每次乘完都要把大于m-1的加到对应项上(i+m-1和i对应)所以好像不能直接多项式快速幂

n是\(10^9\),上个类似快速幂的倍增即可

复杂度是\(O(m \log m \log n)​\)

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cmath>
#define int long long
using namespace std;
const int MOD = 1004535809;
const int G = 3;
const int invG = 334845270;
const int MAXN = 140000;
namespace getG{
int q[100000],cnt=0;
int phi(int n){
int ans=n;
int m=(int)sqrt(n+0.5);
for(int i=2;i<=m;i++){
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0)
n/=i;
}
}
if(n>1)
ans=ans/n*(n-1);
return ans;
}
int my_pow(int a,int b,int mod){
int ans=1;
while(b){
if(b&1)
ans=(1LL*ans*a)%mod;
a=(1LL*a*a)%mod;
b>>=1;
}
return ans;
}
int G(int m){
int Phi = phi(m);
int sq=sqrt(Phi),mid=Phi;
for(int i=2;i<=sq;i++)
if(mid%i==0){
q[++cnt]=Phi/i;
while(mid%i==0)
mid/=i;
}
if(mid>1)
q[++cnt]=Phi/mid;
for(int g=2;1;g++){
int f=true;
if(my_pow(g,Phi,m)!=1)
continue;
else
for(int j=1;j<=cnt;j++){
if(my_pow(g,q[j],m)==1){
f=false;
break;
}
}
if(f)
return g;
}
}
};
int rev[MAXN];
int my_pow(int a,int b){
int ans=1;
while(b){
if(b&1)
ans=(1LL*ans*a)%MOD;
a=(1LL*a*a)%MOD;
b>>=1;
}
return ans;
}
void cal_rev(int n,int lim){
for(int i=0;i<n;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(lim-1));
}
void NTT(int *a,int opt,int n,int lim){
for(int i=0;i<n;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int i=2;i<=n;i<<=1){
int len=i/2;
int tmp=my_pow((opt)?G:invG,(MOD-1)/i);
for(int j=0;j<n;j+=i){
int arr=1;
for(int k=j;k<j+len;k++){
int t=(1LL*a[k+len]*arr)%MOD;
a[k+len]=(a[k]-t+MOD)%MOD;
a[k]=(a[k]+t)%MOD;
arr=(1LL*arr*tmp)%MOD;
}
}
}
if(!opt){
int invN = my_pow(n,MOD-2);
for(int i=0;i<n;i++)
a[i]=(1LL*a[i]*invN)%MOD;
}
}
void mul(int *a,int *b,int &at,int bt){
int num=(at+bt),n=1,lim=0;
while(n<=(num+2))
n<<=1,lim++;
cal_rev(n,lim);
static int tmp[MAXN];
for(int i=0;i<n;i++)
tmp[i]=b[i];
NTT(a,1,n,lim);
NTT(tmp,1,n,lim);
for(int i=0;i<n;i++)
a[i]=(1LL*a[i]*tmp[i])%MOD;
NTT(a,0,n,lim);
at+=bt;
}
void sqr(int *a,int &at){
int num=(at+at),n=1,lim=0;
while(n<=(num+2))
n<<=1,lim++;
cal_rev(n,lim);
static int tmp[MAXN];
for(int i=0;i<n;i++)
tmp[i]=a[i];
NTT(tmp,1,n,lim);
for(int i=0;i<n;i++)
a[i]=(1LL*tmp[i]*tmp[i])%MOD;
NTT(a,0,n,lim);
at=num;
}
void my_pow(int *a,int *b,int n,int m,int k){
static int tmp[MAXN];
for(int i=0;i<=n;i++)
tmp[i]=a[i];
b[0]=1;
int bt=m-1;
while(k){
if(k&1){
mul(b,tmp,bt,n);
for(int i=0;i<m;i++){
b[i]=(b[i]+b[i+m-1])%MOD;
b[i+m-1]=0;
}
for(int i=m;i<=bt;i++)
b[i]=0;
bt=m-1;
}
sqr(tmp,n);
for(int i=0;i<m;i++){
tmp[i]=(tmp[i]+tmp[i+m-1])%MOD;
tmp[i+m-1]=0;
}
for(int i=m;i<=n;i++)
tmp[i]=0;
n=m-1;
k>>=1;
}
}
int n,m,pos[MAXN],S,x,a[MAXN],b[MAXN];
signed main(){
scanf("%lld %lld %lld %lld",&n,&m,&x,&S);
int g=getG::G(m);
for(int i=1,t=1;i<=m-2;i++){
t=(1LL*t*g)%m;
pos[t]=i;
}
for(int i=1;i<=S;i++){
int midx;
scanf("%lld",&midx);
if(midx)
a[pos[midx]]=1;
}
my_pow(a,b,m-1,m,n);
printf("%lld\n",b[pos[x]]);
return 0;
}

P3321 [SDOI2015]序列统计的更多相关文章

  1. P3321 [SDOI2015]序列统计 FFT+快速幂+原根

    \(\color{#0066ff}{ 题目描述 }\) 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S.小C用这 ...

  2. [洛谷P3321][SDOI2015]序列统计

    题目大意:给你一个集合$n,m,x,S(S_i\in(0,m],m\leqslant 8000,m\in \rm{prime},n\leqslant10^9)$,求一个长度为$n$的序列$Q$,满足$ ...

  3. Luogu P3321 [SDOI2015]序列统计

    一道不错的多项式好题.还涉及了一些数论内容. 首先我们看到题目是求乘积模\(m\)的方案数,考虑到这种方案数我们一般都可以用生成函数来做. 但显然卷积的下标有加(FFT,NTT等)有位运算(FWT)但 ...

  4. 洛咕 P3321 [SDOI2015]序列统计

    显然dp就是设\(f[i][j]\)表示dp了i轮,对m取膜是j的方案数 \(f[i][xy\mod m]=f[i-1][x]\times f[i-1][y]\) 这是\(O(nm^2)\)的 像我这 ...

  5. 洛谷P3321 [SDOI2015]序列统计(NTT)

    传送门 题意:$a_i\in S$,求$\prod_{i=1}^na_i\equiv x\pmod{m}$的方案数 这题目太珂怕了……数学渣渣有点害怕……kelin大佬TQL 设$f[i][j]$表示 ...

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

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

  7. [SDOI2015]序列统计

    [SDOI2015]序列统计 标签: NTT 快速幂 Description 给你一个模m意义下的数集,需要用这个数集生成一个数列,使得这个数列在的乘积为x. 问方案数模\(1004535809\). ...

  8. 3992: [SDOI2015]序列统计

    3992: [SDOI2015]序列统计 链接 分析: 给定一个集和s,求多少个长度为n的序列,满足序列中每个数都属于s,并且所有数的乘积模m等于x. 设$f=\sum\limits_{i=0}^{n ...

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

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

随机推荐

  1. 用servlet进行用户名和密码校验1

    运行效果如下: 代码截图: 登陆网页: 显示网页: 网盘链接: 链接:https://pan.baidu.com/s/1g5XJ6y8u5R5Wt0Lkj9g9lg 提取码:bphb

  2. 汇编-13.0-int指令

    1.int指令 int指令的格式为:int n,n为中断类型码,它的功能是引发中断过程. 执行int n指令,相当于引发一个中断号为n的中断过程. (1).取中断类型码n: (2).标志寄存器入栈,I ...

  3. 利用AMPScript获取Uber用户数据的访问权限

    现代项目开发和资产管理方法正在不停地快速变化.在这场创新和扩张的竞赛中,新资产被迅速部署并暴露于公共互联网,已有资产也在不断发展. 要跟上这个不断变化的攻击面是很难的,更不用说保护这些应用程序和系统了 ...

  4. 运维自动化之系统部署 PXE(二)

    PXE介绍 Preboot Excution Environment 预启动执行环境 Intel公司研发 基于Client/Server的网络模式,支持远程主机通过网络从远端服务器下载映像,并由此支持 ...

  5. [MSF]server/capture/http_javascript_keylogger键盘记录

    server/capture/http_javascript_keylogger DEMO使用的官方的效果图: 使用方法: show options 看看 msf auxiliary(server/c ...

  6. 铁大Facebook隐私保护NABCD

    隐私保护功能: N:满足了用户保护自己隐私信息的需求 A:对每一项用户可能需要保护的信息,我们都会添加仅自己可见.指定人可见.部分人可见或所有人可见设置 B:让用户的信息受到更全面的保护,而不仅仅是对 ...

  7. iframe子页面与父页面元素的访问以及js变量的访问

    1.子页面访问父页面元素  parent.document.getElementById('id')和document相关的方法都可以这样用 2.父页面访问子页面元素  document.getEle ...

  8. 软件测试之Soot

    详情请见:https://github.com/fogmisty/SoftwareTest  

  9. web自动化测试python+selenium学习总结----selenium安装、浏览器驱动下载

    一.安装selenium 命令安装selenium库 :pip  install -U selenium 查看selenium是否安装成功:pip list PS:有时会有异常,安装失败,可以尝试去s ...

  10. mvc partialView+kendo window

    在写mvc项目时,一个列表查询页面含有多个操作按钮及弹框操作.原本写在了一个view中,导致代码繁多复杂,难以维护,还有表单赋值清空.验证等麻烦. 因此改用kendo window +partialV ...