不好做不好做,真心不好做。
這個題顯然是dp,一開始我們這樣設計狀態f[
i][j
] 表示長度為i的序列,積在模
m 意義下等於
j的數列的方案數。
那顯然直接做的複雜度是o(
nm2)
,到了這裡,有一種矩陣快速冪做法,可以直接優化到o(
nm3)
,應該能過30%。
顯然正解不允許帶有o(
m3) ,所以矩陣肯定是不行了。
到這裡可能就需要原根了,求出原根,每個數都能表示成原根的冪,這樣就可以用指數代替數,f[
i][j
] 表示長度為
i ,乘積在模
m意義下等於原根的
j 次冪的方案數。
這樣轉移就成了f[
i][j
]→f[
i][j
+kmo
dm−1
],顯然這就是多項式卷積,把f[
i]看做乙個多項式,它的
j 次項乘以另乙個多項式上
k次項上的乙個1,這個乘積會加到結果的第j+
k 次項上去。
很蛋疼的地方在於取模,不取模還好,取模怎麼做。其實也沒啥,每次求完卷積之後肯定會多出來一些不合法的,即它們的下標大於m−
1 ,這個時候只需要把的值加到合法的位置就好了,意思就是f[
imod
m−1]
←f[i
] 。
顯然多項式卷積滿足交換律,所以只需要把用來轉移的那個多項式進行快速冪。
總的時間複雜度o(
mlog
mlog
n)
//dp+ntt
#include
#include
#include
#define maxn 131072
#define mod 1004535809ll
#define ll long long
using namespace std;
ll up, n, m, s[maxn], r[maxn], trans[maxn], f[maxn], inv, tmp[maxn], ans[maxn],
tmp1[maxn], tmp2[maxn], x, pr;
inline ll pow(ll a, ll b, ll p)
void ntt(ll *a, ll n, ll opt)
}if(opt==-1)
}inline void juan(ll *a, ll *b, ll *c)
inline void pow(ll *a, ll b)
}void init()
void work()
}int main()
bzoj3992 SDOI2015 序列統計
time limit 30 sec memory limit 128 mb submit 673 solved 327 submit status discuss 小c有乙個集合s,裡面的元素都是小於m的非負整數。他用程式編寫了乙個數列生成器,可以生成乙個長度為n的數列,數列中的每個數都屬於集合s。...
bzoj3992 SDOI2015 序列統計
小c有乙個集合s,裡面的元素都是小於m的非負整數。他用程式編寫了乙個數列生成器,可以生成乙個長度為n的數列,數列中的每個數都屬於集合s。小c用這個生成器生成了許多這樣的數列。但是小c有乙個問題需要你的幫助 給定整數x,求所有可以生成出的,且滿足數列中所有數的乘積mod m的值等於x的不同的數列的有多...
BZOJ3992 SDOI2015 序列統計
小c有乙個集合s,裡面的元素都是小於m的非負整數。他用程式編寫了乙個數列生成器,可以生成乙個長度為n的數列,數列中的每個數都屬於集合s。小c用這個生成器生成了許多這樣的數列。但是小c有乙個問題需要你的幫助 給定整數x,求所有可以生成出的,且滿足數列中所有數的乘積mod m的值等於x的不同的數列的有多...