SDOI2015 序列統計

2022-05-11 15:40:25 字數 1322 閱讀 9507

容易得到這樣乙個\(dp\),設\(f[i][j]\)表示已經選了\(i\)個數,乘積\(mod \,\,m\)後為\(j\)的方案

\[f[2\times i][j]=\sum_ f[i][a]\times f[i][b]

\]考慮如何優化這個轉移方程,注意到這道題的模數為\(1004535809\),這是乙個很大的提示,考慮\(ntt\)

但是我們知道\(ntt\)處理的是卷積,而這裡是指數相乘,該怎麼轉化呢?

乘法變加法,不由得讓我們想到對數,模意義下的對數,又不由得讓我們想到原根

考慮原根的定義,\(g\)是\(p\)的原根,則\(g^0 ,g^1\dots g^\)在\(mod \,\,p\)下恰好取到\([1,p-1]\)的所有整數

原根也很好求,把\(\varphi(p)=\prod pr_i^\),然後對於所有的\(pr_i\)都有\(g^ \not \equiv 1 \,\, ( mod \,\, p)\)

那麼我們令\(j=\log_g j,a=\log_g a,b=\log_g b\),同時根據擴充套件尤拉定理,轉移方程就變成了

\[f[2\times i][j]=\sum_f[i][a]\times f[i][b]

\]注意每次轉移後\(f[i][j]+=f[i][j+\varphi(m)]\),我們就可以愉快的\(ntt\)啦!

等等,好像還不行,\(n=1e9\),仔細觀察這個轉移,發現可以直接多項式快速冪,那麼再快速冪即可,時間複雜度\(o(m\log m \log n)\)

#include#define int long long

using namespace std;

const int n=3e4+11;

const int mod=1004535809;

int n,m,s,x,len=1,tim;

int f[n],v[n],p[n],pr[n],lg[n];

int read()

while(isdigit(ch))

return x*f;

}int qpow(int x,int y,int p)return re;

}int getrt(int x)

if(phi>1) pr[++tot]=phi;

phi=x-1;

for(int i=2;i<=phi;i++)

return -1;

}void ntt(int *a,int flag)}}

}void mul(int *a,int *b,int *c)

printf("%lld\n",f[lg[x]]);

return 0;

}

SDOI2015 序列統計

time limit 30 sec memory limit 128 mb submit 1829 solved 870 submit status discuss 小c有乙個集合s,裡面的元素都是小於m的非負整數。他用程式編寫了乙個數列生成器,可以生成乙個長度為n的數 列,數列中的每個數都屬於集合...

SDOI2015 序列統計

description 小c有乙個集合s,裡面的元素都是小於m的非負整數。他用程式編寫了乙個數列生成器,可以生成乙個長度為n的數列,數列中的每個數都屬於集合s。小c用這個生成器生成了許多這樣的數列。但是小c有乙個問題需要你的幫助 給定整數x,求所有可以生成出的,且滿足數列中所有數的乘積mod m的值...

SDOI2015 序列統計

點此看題 第一次寫ntt text ntt,被搞自閉了。0x01 樸素dp 設f i j f i j f i j 為選i ii個數乘積為j jj的方案數,轉移如下 f 2 i j f i k f i j inv k f 2i j f i k times f i j times inv k f 2i ...