洛谷P3321 [SDOI2015]序列统计(NTT)
题意:$a_i\in S$,求$\prod_{i=1}^na_i\equiv x\pmod{m}$的方案数
这题目太珂怕了……数学渣渣有点害怕……kelin大佬TQL
设$f[i][j]$表示$\prod_{k=1}^ia_k\equiv j\pmod{m}$的方案数
那么$$f[2*i][j]=\sum_{ab\equiv j\pmod{m}}f[i][a]f[i][b]$$
然后因为$m$是质数。质数有一个叫做原根的东西,质数$p$的原根$g$满足$g^i\ mod\ p$在$i$为$[1,p-1]$时互不相同,然后根据费马小定理$g^{p-1}\equiv 1\pmod{p}$,所以$i$在$[0,p-2]$的范围内$g^{i}$能取遍[1,p-1]的所有数(因为原根一般都特别小,所以可以直接暴力求,这个可以看代码)
因为$g^A\equiv a\pmod{m}$,每一个$A$和$a$互相对应,那么我们可以用$A$来代替$a$
则上式变为$$f[2*i][K]\equiv \sum_{g^Ag^B\equiv g^K\pmod{m}}f[i][A]f[i][B]$$
$$f[2*i][K]\equiv \sum_{g^{A+B}\equiv g^K\pmod{m}}f[i][A]f[i][B]$$
根据费马小定理$a^b\equiv a^{b\ mod\ p-1}\pmod{p}$,可得$$f[2*i][K]\equiv \sum_{g^{(A+B)\ mod\ m-1}=g^K}f[i][A]f[i][B]$$
$$f[2*i][K]\equiv \sum_{A+B\equiv K\pmod{m-1}}f[i][A]f[i][B]$$
设$g[K]=\sum_{A+B=K}f[i][A]f[i][B]$,则$$f[i*2][K]=g[K]+g[K+m-1]$$
然后这个每一层的转移都是一样的,所以用多项式快速幂来计算
//minamoto
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define mul(x,y) (1ll*x*y%P)
#define add(x,y) (x+y>=P?x+y-P:x+y)
#define dec(x,y) (x-y<0?x-y+P:x-y)
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
const int N=,P=;
int n,m,vis[N],F[N],G[N],A[N],B[N],O[N];
int l,limit=,r[N],x,S,pr;
inline int ksm(int a,int b,int P){
int res=;a%=P;
while(b){
if(b&) res=mul(res,a);
a=mul(a,a),b>>=;
}
return res;
}
inline int calc(int x){
//求原根,若只有j=x-1时i^j=1(mod x),i是x的原根
if(x==) return ;
for(int i=;;++i){
bool flag=;
for(int j=;j*j<x;++j)
if(ksm(i,(x-)/j,x)==){flag=false;break;}
if(flag) return i;
}
}
void NTT(int *A,int type){
for(int i=;i<limit;++i)
if(i<r[i]) swap(A[i],A[r[i]]);
for(int mid=;mid<limit;mid<<=){
int R=mid<<,Wn=ksm(,(P-)/R,P);O[]=;
for(int j=;j<mid;++j) O[j]=mul(O[j-],Wn);
for(int j=;j<limit;j+=R){
for(int k=;k<mid;++k){
int x=A[j+k],y=mul(O[k],A[j+k+mid]);
A[j+k]=add(x,y),A[j+k+mid]=dec(x,y);
}
}
}
if(type==-){
reverse(A+,A+limit);
for(int i=,inv=ksm(limit,P-,P);i<limit;++i)
A[i]=mul(A[i],inv);
}
}
void Mul(int *G,int *F){
for(int i=;i<limit;++i) A[i]=G[i],B[i]=F[i];
NTT(A,),NTT(B,);
for(int i=;i<limit;++i) A[i]=mul(A[i],B[i]);
NTT(A,-);
for(int i=;i<m-;++i) G[i]=add(A[i],A[i+m-]); }
void solve(int b){
G[]=;
while(b){
if(b&) Mul(G,F);
b>>=,Mul(F,F);
}
}
int main(){
// freopen("testdata.in","r",stdin);
n=read(),m=read(),x=read(),S=read();
pr=calc(m);
for(int i=,v;i<=S;++i)
vis[v=read()]=;
int pos=-;
for(int i=,j=;i<m-;++i,j=j*pr%m){
if(vis[j]) F[i]=;
if(j==x) pos=i;
}
if(pos==-) return puts(""),;
while(limit<=((m-)<<)) limit<<=,++l;
for(int i=;i<limit;++i)
r[i]=(r[i>>]>>)|((i&)<<(l-));
solve(n);
printf("%d\n",G[pos]%P);
return ;
}
洛谷P3321 [SDOI2015]序列统计(NTT)的更多相关文章
- [洛谷P3321][SDOI2015]序列统计
题目大意:给你一个集合$n,m,x,S(S_i\in(0,m],m\leqslant 8000,m\in \rm{prime},n\leqslant10^9)$,求一个长度为$n$的序列$Q$,满足$ ...
- 洛咕 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)\)的 像我这 ...
- 洛谷3321 SDOI2015 序列统计
懒得放传送[大雾 有趣的一道题 前几天刚好听到Creed_神犇讲到相乘转原根变成卷积的形式 看到这道题当然就会做了啊w 对于m很小 我们暴力找原根 如果你不会找原根的话 出门左转百度qwq 找到原根以 ...
- 【BZOJ3992】[SDOI2015]序列统计 NTT+多项式快速幂
[BZOJ3992][SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属 ...
- BZOJ 3992: [SDOI2015]序列统计 NTT+快速幂
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1155 Solved: 532[Submit][Statu ...
- [SDOI2015]序列统计(NTT+求原根)
题目 [SDOI2015]序列统计 挺好的题!!! 做法 \(f[i][j]\)为第\(i\)个数前缀积在模\(M\)意义下为\(j\) 显然是可以快速幂的:\[f[2*i][j]=\sum\limi ...
- 【BZOJ】3992: [SDOI2015]序列统计 NTT+生成函数
[题意]给定一个[0,m-1]范围内的数字集合S,从中选择n个数字(可重复)构成序列.给定x,求序列所有数字乘积%m后为x的序列方案数%1004535809.1<=n<=10^9,3< ...
- BZOJ3992: [SDOI2015]序列统计(NTT 原根 生成函数)
题意 题目链接 给出大小为\(S\)的集合,从中选出\(N\)个数,满足他们的乘积\(\% M = X\)的方案数 Sol 神仙题Orz 首先不难列出最裸的dp方程,设\(f[i][j]\)表示选了\ ...
- P3321 [SDOI2015]序列统计
思路 首先有个挺显然的DP \[ dp[i][(j*k)\%m]+=dp[i-1][j]\times dp[i-1][k] \] 想办法优化这个DP 这个dp也可以写成这样 \[ dp[i][j]=\ ...
随机推荐
- 同一世界服务器架构--Erlang游戏服务器
Erlang最大的优点是方便,很多基础功能都已经集成到Erlang语言中.之前用C++写服务器的时候,管理TCP连接很繁琐,需要写一大堆代码来实现.底层的框架需要写很多代码实现,这样既浪费时间 ...
- Scrapyd部署
从github(https://github.com/scrapy/scrapyd)下载安装包放到D:\python\Lib\site-packages\ 解压压缩包:cd 到解压目录 python ...
- 预料外的变量值的改变是很多bug的源头
- 面试算法爱好者书籍/OJ推荐
面试算法爱好者书籍/OJ推荐 这个书单也基本适用于准备面试. 一.教科书 基本上一般的算法课本介绍的范围都不会超出算法导论和算法引论的范围.读完这两本书,其它的算法课本大致翻翻也就知道是什么货色了. ...
- Xcode工程断点调试失效
1.我解决的是方法是,选择Product---->Edit Scheme------>(这里进入后会有Info,Arguments,Options,Diagnostics)选择Info-- ...
- stm32 USART使用标志
在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器,另一个是程序看不到的移位寄存器,对应USART数据发送有两个标志,一个是TXE=发送数据寄存器空,另一个是TC=发送结束. ...
- HDU4990 Reading comprehension —— 递推、矩阵快速幂
题目链接:https://vjudge.net/problem/HDU-4990 Reading comprehension Time Limit: 2000/1000 MS (Java/Others ...
- OJ提交题目中的语言选项里G++与C++的区别
一.OJ提交题目中的语言选项里G++与C++的区别 http://www.th7.cn/Program/cp/201405/199001.shtml 首先更正一个概念,C++是一门计算机编程语言,G+ ...
- 【C/C++】任意大于1的整数分解成素数因子乘积的形式
// #include<stdio.h> #include<math.h> #include<malloc.h> int isprime(long n); void ...
- python中字符串的内置方法
这里说的是字符串中的内置方法,毕竟字符串是最常用的操作对象. ['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '_ ...