題目傳送門
給出 \(n,m,k\) ,表示有乙個 \(n\times m\) 的網格,第 \(k\) 行已經確定了,每個格仔只能填 \(1,2,3\),但是必須滿足相鄰格仔顏色不同,問有多少種合法方案。
\(1\le k\le n\le 10^4,m\le 5\)
因為這道題目並不難,所以這篇部落格主要講如何卡到 \(\text\)(至少在2020-09-17還是,希望還有線性方法的出現吧,感覺非線性做法已經壓到極致了)
很顯然,我們可以設 \(dp[i][s]\) 表示第 \(i\) 行狀態為 \(s\) 的方案數。初始顯然,轉移顯然。下面講優化。
經實測,可以優化 \(20ms\) 左右。
可以處理出哪些狀態合法,已經每個狀態可以從哪些狀態轉移過來。後者可以用 \(\text\) 儲存下來。
你發現合法的狀態最多只有 \(3\times 2^\le48\) 個,你可以先搜尋一波,然後預處理的時候只考慮這 \(48\) 之間的關係就好了。
此時時間複雜度已經降為了 \(\theta((3\times 2^m)^2n)\) 。
你發現這個東西可以矩陣優化,顯然,時間複雜度降為 \(\theta(27\times 8^m\times \log n)\)
注意:矩陣乘法的時候先用 \(\text\) 運算,這樣可以減少取模次數
#pragma gcc optimize("o3")
#include using namespace std;
#define int register int
#define ll long long
#define mod 1000000
#define maxn 6
template inline void read (t &t)while (c >= '0' && c <= '9') t *= f;}
template inline void read (t &t,args&... args)
template inline void write (t x)if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template void add (t &a,int b)
vector g[50];bool vis;
int n,m,k,tot,sta,ans,nows,s[5],ind[50],dp[2][50];
void dfs (int x,int las,int sta)
ll tmp[50][50];
struct matrix
int * operator (int key)
matrix operator * (const matrix &p)const
}a,b,c;
matrix operator ^ (matrix a,int b)
signed main()
if (flag) a[i][j] = a[j][i] = 1;
} a[i][0] = 1;
} b[bel][0] = 1;
for (int i = 1;i <= tot;++ i) b[bel][i] = a[bel][i];
c = (a ^ (k - 1)) * b * (a ^ (n - k));
for (int i = 1;i <= tot;++ i) add (ans,c[i][0]);
write (ans),putchar ('\n');
return 0;
}
一本通 5 1 練習 1 括號配對
plysc 記憶體限制 512 mib 時間限制 1000 ms 標準輸入輸出 題目型別 傳統 評測方式 文字比較 上傳者 1bentong 題目描述 hecy 又接了個新任務 be 處理。be 中有一類被稱為 gbe。以下是 gbe 的定義 空表示式是 gbe 如果表示式a是 gbe,則 a 與 ...
一本通 1 1 練習 1 數列極差
題目傳送門 這題也是典型的貪心演算法題。對於這個問題 先通過例項來認識問題所描述的計算過程。令 n 3 取數列 3,5,7 可能有下面三種情況 3 5 1 7 1 113 3 7 1 5 1 111 5 7 1 3 1 109 由此可見先運算小資料的到的是最大值,先運算大資料得到的是最小值。故針對此...
一本通 3 1 練習 4 Tree 題解
題目位址 第一眼看到此題,感覺就是一道水題,直接加上前nee dneed need 小的白邊就行了,再處理到n 1 n 1n 1條黑邊,但是,打完後突然發現有問題。雖然加上了前nee dneed need 小的白邊,但是會出現樹不連通的現象,即無法構成生成樹。正解思路 二分乙個增量mid midmi...