SDOI2015 序列統計

2022-09-02 13:39:06 字數 1620 閱讀 3184

小c有乙個集合\(s\),裡面的元素都是小於\(m\)的非負整數。他用程式編寫了乙個數列生成器,可以生成乙個長度為\(n\)的數列,

數列中的每個數都屬於集合\(s\)。小c用這個生成器生成了許多這樣的數列。但是小c有乙個問題需要你的幫助:

給定整數\(x\),求所有可以生成出的,且滿足數列中所有數的乘積\(\mod m\)的值等於\(x\)的不同的數列的有多少個。

小c認為,兩個數列\(\\)和\(\\)不同,當且僅當至少存在乙個整數\(i\),滿足\(a_i\neq b_i\)。

另外,小c認為這個問題的答案可能很大,因此他只需要你幫助他求出答案\(\mod 1004535809\)的值就可以了。

一行,四個整數,\(n、m、x、|s|\),其中\(|s|\)為集合\(s\)中元素個數。

第二行,\(|s|\)個整數,表示集合\(s\)中的所有元素。

\(1 \leq n \leq 10^9,3 \leq m \leq 8000\),m為質數

\(0 \leq x \leq m-1\),輸入資料保證集合s中元素不重複\(x \in [1,m-1]\)

集合中的數$ \in [0,m-1]$

一行,乙個整數,表示你求出的種類數\(\mod 1004535809\)的值。

看到這題。。首先很容易列出乙個dp轉移方程

令\(f_\)表示選了\(i\)個數字,當前乘積為\(j\)的種類數

\[f_=\sum_ *f_}

\]我們發現它非常不優美,複雜度高達$ o (n * m^2) $

我們發現這個式子可以倍增。。於是很輕鬆的乾掉乙個n,它的複雜度變成了$ o(\log n * m^2) $

這貌似還是有點多。。考慮如何乾掉乙個 $ m $

咦。。這個模數貌似有點熟悉。。考慮ntt

不過這是乘法。。我們做不了ntt 。。。

考慮原根

設\(p\)為\(m\)的原根。。那麼\(p\)的冪次可以表示出\([1,m)\)的所有數字————原根定義

於是dp方程變成了這樣

\[f_=\sum_*f_}

\]注意。。此時\(f_\)表示選到第\(i\)個數,大小為\(p^j\)次的方案數

再一變\[f_=\sum_*f_}

\]我們發現這玩意長得像個卷積。。可以用ntt了

於是複雜度變成了 $ o(m \log n log m)$

#include#include#includeusing namespace std;

int n,m,x,lens,g[2000000],a[2000010],b[2000010];

int f[2000010],ans[2000010];

int fpow(int x,int k,int mod)

return ans;

}namespace getroot //求原根

int find(int p)

}if (x!=1) prime[++cnt]=x;

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

if (check(i,p)) return i; }}

namespace ntt

printf("%d\n",ans[x]);

}int main()

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 ...