[SDOI2015]序列統計
阿新 • • 發佈:2018-02-09
-m sig i++ 同余 cto fast 數列 splay 如何
而這裏是\[a_i\times b_j=c_{i*j}\]
怎麽辦呢?
註意到題目中給出的\(m\)一定是個質數
因此我們可以把每個\(<m\)的數當作\(m\)的原根\(g\)對應的次冪
於是當\(i=g^{M_i}\)(這裏\(M\)是一個映射)時就可以對應的求出其原值和對應原根的次冪
題面在這裏
題意
求長度為\(n\),元素取值集合為\(S(\forall x\in S \in [1,m-1])\)的數列乘積為\(x\)的方案數
sol
首先我們可以想到一個\(DP\):設\(f[i][j]\)表示長度為\(i\)的數列乘積為\(j\)的方案數,那麽有:
\[f[i][j]=\sum_{k|j}(f[i-1][k]\times sum[\frac{j}{k}])\]
其中\(sum[i]\)表示集合\(S\)中與\(i\) \(mod\) \(m\)同余的數的個數
由於每\(f[i-1]->f[i]\)的轉移是固定的,那麽可以使用矩乘優化
考慮如何進一步優化:我們發現這很像一個卷積的形式,因此考慮NTT快速冪
但卷積的形式為\[a_i\times b_j=c_{i+j}\]
而這裏是\[a_i\times b_j=c_{i*j}\]
怎麽辦呢?
註意到題目中給出的\(m\)一定是個質數
因此我們可以把每個\(<m\)的數當作\(m\)的原根\(g\)對應的次冪
於是當\(i=g^{M_i}\)(這裏\(M\)是一個映射)時就可以對應的求出其原值和對應原根的次冪
快速冪的時候註意需要對\(\ge m\)次冪的系數取模
#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-10;
const int mod=1004535809;
const int g=3;
const int inv=334845270;
const int N=40010;
il ll read(){
RG ll data=0,w=1;RG char ch=getchar();
while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘))ch=getchar();
if(ch==‘-‘)w=-1,ch=getchar();
while(ch<=‘9‘&&ch>=‘0‘)data=data*10+ch-48,ch=getchar();
return data*w;
}
il void file(){
//freopen("a.in","r",stdin);
//freopen("b.out","w",stdout);
}
il int getg(int p){
RG int ret,b;
for(RG int i=2;;i++){
ret=b=1;
for(RG int j=1;j<p-1;j++){
ret=1ll*ret*i%p;if(ret==1){b=0;break;}
}
if(b)return i;
}
}
il ll poww(ll a,ll b){
RG ll ret=1;
for(a%=mod;b;b>>=1,a=a*a%mod)if(b&1)ret=ret*a%mod;
return ret;
}
namespace NTT{
int n,l,r[N],rev;
il void NTT(int *A,int n,bool b){
for(RG int i=0;i<n;i++)if(i<r[i])swap(A[i],A[r[i]]);
for(RG int i=2;i<=n;i<<=1){
RG int w=poww((b?g:inv),(mod-1)/i);
for(RG int j=0;j<n;j+=i){
RG int wn=1;
for(RG int k=j;k<j+(i>>1);k++,wn=1ll*wn*w%mod){
RG int x=1ll*wn*A[k+(i>>1)]%mod;
A[k+(i>>1)]=(A[k]-x+mod)%mod;
A[k]=(A[k]+x)%mod;
}
}
}
if(!b)for(RG int i=0;i<n;i++)A[i]=1ll*A[i]*rev%mod;
}
il void conv(int *A,int *B,int n,int len){
NTT(A,n,1);if(A!=B)NTT(B,n,1);
for(RG int i=0;i<n;i++)A[i]=1ll*A[i]*B[i]%mod;
NTT(A,n,0);if(A!=B)NTT(B,n,0);
for(RG int i=0;i<len;i++)
if(A[i+len])A[i]=(A[i]+A[i+len])%mod,A[i+len]=0;
}
il void fastpow(int* A,int* B,int t,int len){
for(n=1;n<=len*2;n<<=1)l++;rev=poww(n,mod-2);
for(RG int i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((1&i)<<(l-1));
while(t){if(t&1)conv(A,B,n,len);conv(B,B,n,len);t>>=1;}
}
}
int n,m,x,S,s[N],f[N];
map<int,int>M;
il void init(){
RG int G=getg(m),ret=1;
for(RG int i=0;i<m-1;i++){M[ret]=i;ret=1ll*ret*G%m;}
}
int main()
{
file();n=read();m=read();x=read();S=read();init();
for(RG int i=1,k;i<=S;i++)if(k=read())s[M[k]]++;f[0]=1;
NTT::fastpow(f,s,n,m-1);
printf("%d\n",f[M[x]]);
return 0;
}
[SDOI2015]序列統計