SDOI2015 序列統計

2021-10-01 16:10:40 字數 3833 閱讀 3129

傳送門 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(計算一次迴圈卷積的複雜度×

log⁡n)

\times\log n)

×logn)(m

2)

\mathcal o(m^2)

o(m2

)硬算。

(所以如果有大佬知道這種東西怎麼算,也請周知)

然後我t

tt了。

換乙個思路,想辦法把它搞成普通卷積,這樣就可以用fft/ntt

\text

fft/ntt

優化了。

仔細考慮m

mm為質數這一條件,這有什麼意義呢?它的意義是,我們可以求離散對數

離散對數就是這樣的東西:log⁡a

b=x⇔

ax≡b

\log_a b= x\leftrightarrow a^x\equiv b

loga​b

=x⇔a

x≡b(似乎符號並不是log

⁡\log

log……但是我不知道是什麼了)

在離散對數的意義下,a×b

=g

log⁡ga

×g

log⁡gb

≡g

log⁡ga

+log⁡g

b(mo

dm

)a\times b=g^\times g^\equiv g^\pmod

a×b=

glogg​

a×glogg​

b≡glogg​

a+logg​b

(mod

m)發現指數就已經寫成了卷積的形式。那麼就可以做了。問題是g

gg選擇什麼呢?

選擇 m

mm的原根。只有這樣,∀a∈

[1,m

),

log⁡ga

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