SDOI2015 序列統計

2021-10-01 13:41:21 字數 3544 閱讀 7316

點此看題

第一次寫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][

j]=f

[i][

k]×f

[i][

j×in

vk​]

這個轉移是無法優化的,時間複雜度o

(log⁡n

m2

)o(\log nm^2)

o(lognm2

),無法優化。

受到這道題的啟發,我們需要把乘轉化為加然後套卷積。

0x02 原根的引入

對於乙個質數m

mm,如果gi%

mg^i\%m

gi%m

,i

ii取[0,

m−2]

[0,m-2]

[0,m−2

],gg

g兩兩不同,那麼就稱g

gg是m

mm的乙個原根,原根有很多神奇的性質,比如:gi×

gj=g

i+

jg^i\times g^j=g^

gi×gj=

gi+j

,g m−

1=

1g^=1

gm−1=1

我們可以利用原根,重新定義dpdp

dp方程,f[i

][j]

f[i][j]

f[i][j

]為選i

ii個數,它們的乘積所對應的原根指數為j

jj,轉移如下:

f [2

i][j

]=f[

i][k

]+f[

i][(

j−k+

m−1)

%(m−

1)

]f[2i][j]=f[i][k]+f[i][(j-k+m-1)\%(m-1)]

f[2i][

j]=f

[i][

k]+f

[i][

(j−k

+m−1

)%(m

−1)]

這個方程就可以用卷積來優化,由於這道題要膜1004535809

1004535809

100453

5809

,我們選擇ntt

\text

ntt。

現在還有乙個問題,就是如何求原根,由於aφ(

m)=1

modm

a^=1\mod m

aφ(m)=

1mod

m,所以φ(m

)\varphi(m)

φ(m)

是乙個迴圈節,原根就要滿足[0,

m−2]

[0,m-2]

[0,m−2

]中沒有迴圈節,而更小的迴圈節一定存在於φ(m

)\varphi(m)

φ(m)

的因數中,列舉所有數作為可能的原根,在列舉φ(m

)\varphi(m)

φ(m)

所有的因數判斷迴圈節,就可以找出原根,這也是這道題m

mm很小並且是質數的原因。

0x03 tips

這道題資料有鍋,輸入的0

00要被忽略。

#include

#include

#include

#define int long long

using

namespace std;

const

int maxn =

20005

;const

int mod =

1004535809

;int

read()

int n,m,x,s,g,mp[maxn]

,a[maxn]

,b[maxn]

,r[maxn]

,rev[maxn]

;int

qkpow

(int a,

int b,

int mod=mod)

return res;

}int

get_rt

(int x)

if(phi>

1) fac[

++tot]

=phi;

phi=x-1;

for(

int i=

2;i<=phi;i++

)return0;

}void

ntt(

int*a,

const

int len,

int tmp)

for(

int s=

2;s<=len;s<<=1)

}}if(tmp==1)

return

;int inv=

qkpow

(len,mod-2)

;for

(int i=

0;i) a[i]

=a[i]

*inv%mod;

}void

mul(

int*a,

int*b,

int*c)

,b[maxn]

=,len=1;

while

(len<=

2*m) len<<=1;

for(

int i=

0;i1;i++

) a[i]

=a[i]

;for

(int i=

0;i1;i++

) b[i]

=b[i]

;ntt

(a,len,1)

;ntt

(b,len,1)

;for

(int i=

0;i) a[i]

=a[i]

*b[i]

%mod;

ntt(a,len,-1

);for(

int i=

0;i1;i++

) c[i]

=(a[i]

+a[i+m-1]

)%mod;

}signed

main()

while

(n>0)

//多項式的快速冪,優化dp

printf

("%lld\n"

,r[mp[x]])

;}

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

SDOI 2015 序列統計

在遭受了巨大的精神打擊後,我決定了,要做乙個壓行的好孩子!部落格如果有不對之處,請一定要指出啊啊啊啊啊謝謝謝謝謝大佬!我們首先可以寫出乙個遞推式 f a c b d取 模mod f a b f c d f a c b d取模mod f a b f c d f a c b d 取模mo d f a b...