傳送門 to bzoj
傳送門 to vj
首先考慮這道題怎麼用生成函式做。
顯然,如果用fk(
x)=∑
i=0m
−1ak
ix
if_k(x)=\sum_^a_ x^i
fk(x)
=∑i=
0m−1
aki
xi做生成函式(aki
a_ak
i表示積為i
ii、長度為k
kk的數列的數量),那麼一定有fk(
x)=f
k−r(
x)∗f
r(x)
f_k(x)=f_(x)*f_r(x)
fk(x)
=fk−
r(x
)∗fr
(x)
此處是迴圈狄利克雷卷積;也即,(f∗
g)(x
)=∑a
b≡x(
modm
)f(a
)g(b
)(f*g)(x)=\sum_}f(a)g(b)
(f∗g)(
x)=∑
ab≡x
(mod
m)f
(a)g
(b)
然後你心想,f
1f_1
f1是極其簡單的;於是答案就是f1n
(x
)f_1^n(x)
f1n(x
) 複雜度就是o
(\mathcal o(
o(計算一次迴圈卷積的複雜度×
logn)
\times\log n)
×logn)(m
2)
\mathcal o(m^2)
o(m2
)硬算。
(所以如果有大佬知道這種東西怎麼算,也請周知)
然後我t
tt了。
換乙個思路,想辦法把它搞成普通卷積,這樣就可以用fft/ntt
\text
fft/ntt
優化了。
仔細考慮m
mm為質數這一條件,這有什麼意義呢?它的意義是,我們可以求離散對數。
離散對數就是這樣的東西:loga
b=x⇔
ax≡b
\log_a b= x\leftrightarrow a^x\equiv b
logab
=x⇔a
x≡b(似乎符號並不是log
\log
log……但是我不知道是什麼了)
在離散對數的意義下,a×b
=g
logga
×g
loggb
≡g
logga
+logg
b(mo
dm
)a\times b=g^\times g^\equiv g^\pmod
a×b=
glogg
a×glogg
b≡glogg
a+loggb
(mod
m)發現指數就已經寫成了卷積的形式。那麼就可以做了。問題是g
gg選擇什麼呢?
選擇 m
mm的原根。只有這樣,∀a∈
[1,m
),
logga
\forall a\in[1,m),\log_g a
∀a∈[1,
m),logg
a都是有定義的。
然後就是ntt
\text
ntt的板題了。不難發現,模數1004535809
1004535809
100453
5809
是有原根的,為333.
#include
#include
#include
using
namespace std;
inline
intreadint()
inline
intqkpow
(long
long base,
int q,
int mod)
vector<
int> ys;
inline
intgetyg
(int p)
if(n !=
1) ys.
push_back
(n);
for(
int i=
2,len=ys.
size()
; i++i)
if(ok)
return i;
}return-1
;// 不存在的
}const
int maxm =
8005
<<2;
// 乘4,ntt要用到
int n, m, x, has[maxm]
;// 離散對數
int yg;
// 原根
int cnt[maxm]
;void
input()
else has[0]
= m-1;
// base在拷貝的時候,將會忽略它
while
(s --
) cnt[has[
readint()
]]++;
}const
int mod =
1004535809
;// 原根為3
int omg[maxm]
=, d[maxm]
;void
ntt(
int a,
int n,
int opt)
for(
int len=
2; len<=n; len<<=1)
for(
int*p=a; p!=a+n; p+
=len)
for(
int i=
0; i<
(len>>1)
;++i)
if(opt ==-1
)}int tmp[maxm]
;void
multiply
(int a,
int b)
static
int n =1;
// a *= b
if(n ==1)
while
(n <=
(m<<1)
) n <<=1;
for(
int i=
0; i++i) tmp[i]
= b[i]
;ntt
(a,n,1)
,ntt
(tmp,n,1)
;for
(int i=
0; i++i)
a[i]
=1ll
*a[i]
*tmp[i]
%mod;
ntt(a,n,-1
);for(
int i=
0; i++i)
// 迴圈卷積
a[i]
=(a[i]
+a[i+
(m-1)]
)%mod;
for(
int i=m-
1; i++i) a[i]=0
;}int ans[maxm]
, base[maxm]
;void
solve()
intmain()
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 ...