luogu1357 花園 狀態壓縮 矩陣快速冪

2022-06-30 07:45:09 字數 1474 閱讀 7817

小l有一座環形花園,沿花園的順時針方向,他把各個花圃編號為1~n(2<=n<=10^15)。他的環形花園每天都會換乙個新花樣,但他的花園都不外乎乙個規則,任意相鄰m(2<=m<=5,m<=n)個花圃中有不超過k(1<=k我們先不考慮環。我對狀態的設計是f(i, j, k),i是以第i位起始,j是區間[i, i+m]中最後乙個c的位置-i的值,k是[i, i+m]中c的數量,f是排列的種數。後來我認為j也不需要,f(i, k)就行了。但是此方法乙個k無法表示出具體的排布狀態,這是錯誤的。

我們看到m<=5,很容易想到用狀態壓縮來表示具體的狀態。所以我們設計出f(i, s),i是位置,s是[i, i+m]中c的排布狀態,f是排列的個數。遞推式f(i + 1, s >> 1) += f(i, s), f(i + 1, (s >> 1) | (1 << m - 1) += f(i, s),其中涉及到的所有集合內元素個數都不超過k。

我當時想到將長度為n的序列尾部再加乙個長度為m的序列,從左往右遞推,最後輸出的結果便是sum,s滿足元素個數<=k,但考慮到這樣會導致結尾m個花的排列狀態和開頭m個花的排列狀態不一致而導致錯誤。於是我就卡住了。

正確的解決辦法是列舉開頭[1, m]的花的狀態s,每次將其固定住,這樣dp推導出的dp(n, s)都是由[m + 1, n + m]處花合法的排列得出的了。

我們看到對於每乙個狀態s0,無論i是多少,可以使f(i, s0)去+=的出處f(i+1, s0')都是固定的。所以我們建立乙個矩陣a,a(s1, s2)=[對任意i, f(i + 1, s2)需要+=f(i, s1)]。內判斷為真即1,否則為0。這樣,對於每乙個開頭[1, m]的花的狀態s0,建立乙個向量b,其中只有s0那一位的項為1(排列方式由s0知道肯定為1),最終的結果便是b*a^n。最後求和即可。

#include #include #include #include using namespace std;

#define ll long long

const int max_m = 7;

const ll p = 1000000007;

ll n, m, k;

struct matrix

matrix(int totrow, int totcol) :totrow(totrow), totcol(totcol)

matrix operator * (const matrix& a) const

matrix power(ll n)

return ans;

}};int main()

static matrix g(1 << m, 1 << m);

for (int s = 0; s < (1 << m); s++)

}static matrix powed = g.power(n), start(1, 1 << m);

ll ans = 0;

for (int s = 0; s < (1 << m); s++)

}printf("%lld\n", ans);

}

洛谷P1357 花園(狀態壓縮 矩陣快速冪)

小l有一座環形花園,沿花園的順時針方向,他把各個花圃編號為1 n 2 n 10 15 他的環形花園每天都會換乙個新花樣,但他的花園都不外乎乙個規則,任意相鄰m 2 m 5,m n 個花圃中有不超過k 1 k例如,n 10,m 5,k 3。則 ccpcppppcc 是一種不符合規則的花圃 ccpppp...

P1357 花園 矩陣快速冪 DP

題意 乙個只含字母c和p的環形串 求長度為n且每m個連續字元不含有超過k個c的方案數 m 5 n 1e15 題解 用乙個m位二進位制表示狀態 轉移很好想 但是這個題是用矩陣快速冪加速dp的 因為每一位的轉移都是一樣的 用乙個矩陣表示狀態i能否轉移到狀態j 然後跑一遍 統計答案特別講究 因為是乙個環 ...

狀壓dp 矩陣 洛谷 P1357 花園

簡單來說,這一題就是乙個狀壓dp用矩陣優化 但是這個矩陣也是最最最基礎的矩陣了 floyd矩陣 dp的話,和第乙個題解hi一樣的 f i s 表示第i位時的方案,s為i i m 1的狀態 然後轉移的時候我們列舉i列舉2個s if v j k f i j f i j f i 1 k mo 這裡的v j...