DP 壓縮矩陣 矩陣乘法 閱讀

2021-06-21 05:41:52 字數 1575 閱讀 4451

【湖南集訓】閱讀 ——by hta

【問題描述】

現在,小g 想統計共有多少權值不超過n 的不同的單詞。

n <= 10000000

【題解】

很容易想到乙個dp,f[i][j]表示權值為i時以字母j結尾有多少鐘不同的方案。

f[i][j] = σf[i-w[i][k]][k];

這演算法時間複雜度為26*26*n,對於n<=10000000是無法承受的。

對於這種沒有條件轉移的dp方程,我們很容易想到用矩陣來優化速度。

可是本題dp方程一眼看去轉移時i和j的都在變化,好像很難用矩陣優化。

但是經過仔細閱讀題目,我們發現w[i][k] <= 5,這就啟發我們將二維轉移壓縮成一維的。

對於f[i][j],我們只可由f[i-1][k],f[i-2][k],f[i-3][k],f[i-4][k],f[i-5][k]轉移得到,所以我們把f[i-5],f[i-4],f[i-3],f[i-2],f[i-1]壓成乙個5*26的一位矩陣。

則我們的轉移變成由f[i-5],f[i-4],f[i-3],f[i-2],f[i-1] 轉移到 f[i-4],f[i-3],f[i-2],f[i-1],f[i]。

轉移矩陣是(5*26)*(5*26)的,可以由w[i][k]構造。

因為題目說要求權值不超過n的,所以另外我們還需新增乙個終結節點,把所有字母向它連,它自己也向自己連。

(具體細節看**)。

另外做這種較大的矩陣乘法時要注意棧空間,應寫非遞迴,而且要避免過多的中間變數,能開全域性變數最好開全域性的。

#include#include#include#define fo(i,a,b) for (int i = a;i <= b;i ++)

using namespace std;

typedef long long ll;

const int p = 1000000007;

const int maxn = 1000005;

int n,m,w[27][27],ans;

struct matrix

tr,ans,ret;

inline matrix operator*(const matrix &a,const matrix &b)

void pow(int exp) }

void initialize()

fo(i,1,26) fo(j,1,26)

if (!w[i][j]) w[i][j] = 1;

fo(i,105,130) ans.x[1][i] = 1;

fo(i,1,26) fo(j,1,26)

tr.x[105-26*(w[i][j]-1)+i-1][105+j-1] = 1;

fo(i,27,130) tr.x[i][i-26] = 1;

fo(i,105,130) tr.x[i][131] = 1;

tr.x[131][131] = 1;

ans.r = 1; ans.h = 131;

tr.r = 131; tr.h = 131;

}void work()

int main()

壓縮矩陣乘法

矩陣是乙個二維平面的概念,而壓縮矩陣就是要把這個平面進行壓縮,即用一維陣列來表示二維陣列。那應該怎樣來表示二維陣列?我們知道二維陣列都有乙個行列下標i和j,而一維陣列只有乙個下標k,我們只需要將k用i和j來表示,得到對應的關係式,就可以將矩陣儲存到一維陣列了 對應的關係是這樣的 1.二維矩陣和一維矩...

矩陣鏈乘法 DP

矩陣鏈乘法是這樣的問題 給定n個矩陣 a1,a2,an,其中ai與ai 1是可乘的,i 1,2 n 1。確定計算矩陣連乘積的計算次序,使得依此次序計算矩陣連乘積需要的數乘次數最少。輸入資料為矩陣個數和每個矩陣規模,輸出結果為計算矩陣連乘積的計算次序和最少數乘次數。我們稱有如下性質的矩陣乘積鏈為完全括...

dp矩陣鏈乘法

dp矩陣鏈乘法 矩陣a和b可乘的條件是矩陣a的列數等於矩陣b的行數。給定n個矩陣 a1,a2,an 其中ai與ai 1是可乘的,i 1,2 n 1。如何確定計算矩陣連乘積的計算次序,使得依此次序計算矩陣連乘積需要的數乘次數最少。輸入描述 首先輸入乙個n,表示幾個矩陣。換行輸入矩陣。輸出描述先輸出矩陣...