1. 程式人生 > >[SDOI2015]序列統計

[SDOI2015]序列統計

-m sig i++ 同余 cto fast 數列 splay 如何

題面在這裏

題意

求長度為\(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]序列統計