洛谷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]=\ ...
随机推荐
- MySQL 数据类型转换
版权个人所有,欢迎转载如转载请说明出处.(东北大亨) http://www.cnblogs.com/northeastTycoon/p/5505523.html 网络越来越达到所以带来的好处不容置疑. ...
- 九度OJ 1123:采药 (01背包、DP、DFS)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2705 解决:1311 题目描述: 辰辰是个很有潜能.天资聪颖的孩子,他的梦想是称为世界上最伟大的医师. 为此,他想拜附近最有威望的医师为师 ...
- Android Touch事件分发
跟touch事件相关的3个方法: public boolean dispatchTouchEvent(MotionEvent ev); //用来分派event public boolean onInt ...
- PAT 天梯赛 L1-049. 天梯赛座位分配 【循环】
题目链接 https://www.patest.cn/contests/gplt/L1-049 思路 用一个二维数组来保存一个学校每个队员的座位号 然后需要判断一下 目前的座位号 与该学校当前状态下最 ...
- 使用单例模式设计PDO数据操作类
<?php /** * MyPDO * @author LHL <506698615@qq.com> * @date 2016.04.20 */ class MyPDO{ prote ...
- user版本如何永久性开启adb 的root权限【转】
本文转载自:http://blog.csdn.net/o0daxu0o/article/details/52933926 [Solution]* adb 的root 权限是在system/core/a ...
- 让tomcat启动时,自动加载你的项目
在tomcat-->conf-->serve.xml文件最后加上 <Context path="/atest" docBase="E:\Workspac ...
- C#继承与多态
继承:在程序中,如果一个类A:类B,这种机制就是继承. 子类可以继承父类的所有内容(成员)吗? 解析: 1.私有成员(属性和方法) 2.构造函数 3.final修饰过的方法,子类不能进行重写 //SE ...
- Relocation POJ-2923
题目链接 题目意思: 有 n 个货物,并且知道了每个货物的重量,每次用载重量分别为c1,c2的火车装载,问最少需要运送多少次可以将货物运完. 分析:本题可以用二进制枚举所有不冲突的方案,再来dp 一下 ...
- io_service work 的作用
当有任务的时候,run函数会一直阻塞:但当没有任务了,run函数会返回,所有异步操作终止. 客户端程序中,如果我想连接断开后重连,由于连接断开了,run会返回,当再次重连的时候,由于run返回了,即使 ...