【湖南集訓】閱讀 ——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,表示幾個矩陣。換行輸入矩陣。輸出描述先輸出矩陣...