「考前日誌」11.17
阿新 • • 發佈:2020-11-17
總結
還是不對勁
打不起精神頭來
而且電腦還巨卡
⑨⑨⑤⑧
今日已完成
-
AcWing291 蒙德里安的夢想
狀壓DP。
以行數以及此行的形態為狀態。
設 \(f_{i,j}\) 表示前 \(i\) 行,第 \(i\) 行形態為 \(j\) 時的方案總數。
此處 \(j\) 是一個用十進位制整數記錄的 \(m\) 位二進位制數。
如果 \(j\) 二進位制下當前位置為 \(1\),說明該位置為某個小長方形的上半部分,下一行的當前位置一定要放下半部分(即為 \(0\))。
如果為 \(0\) 表示其他情況,對下一行的形態無影響,但要保證連續的 \(0\) 的個數為偶數個。
對於當前行 \(i\) 的形態 \(j\)- 當前行的形態 \(j\) 與上一行的形態 \(k\) 的與運算結果為 \(0\)。
這樣保證了上一行形態中為 \(1\) 的位對應的當前位一定為 \(0\),滿足上述條件。 - \(j\) 和 \(k\) 的按位或運算的二進位制表示中連續 \(0\) 的個數為偶數個。
這樣也就說明\(j\) 和 \(k\) 的二進位制表示中連續 \(0\) 的個數為偶數個。
預處理合法(即連續 \(0\) 為偶數)的狀態,然後 dp 即可。
\[f_{i,j}=\sum\limits_{j\&k=0且j|k合法}f_{i-1,k} \]#include <map> #include <cmath> #include <queue> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> #define ll long long using namespace std; const int A = 1e5 + 11; const int B = 1e6 + 11; const int mod = 1e9 + 7; const int inf = 0x3f3f3f3f; inline int read() { char c = getchar(); int x = 0, f = 1; for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1; for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return x * f; } int n, m; bool ok[A]; ll f[12][1 << 11]; int main() { while (cin >> n >> m) { if (n == 0 && m == 0) return 0; memset(f, 0, sizeof(f)); for (int i = 0; i < (1 << m); i++) { bool cnt = 0, has_odd = 0; for (int j = 0; j < m; j++) if (i >> j & 1) has_odd |= cnt, cnt = 0; else cnt ^= 1; ok[i] = !(has_odd | cnt); } f[0][0] = 1; for (int i = 1; i <= n; i++) { for (int j = 0; j < (1 << m); j++) { for (int k = 0; k < (1 << m); k++) if ((j & k) == 0 && ok[j | k]) f[i][j] += f[i - 1][k]; } } cout << f[n][0] << '\n'; } }
- 當前行的形態 \(j\) 與上一行的形態 \(k\) 的與運算結果為 \(0\)。
-
AcWing289 環路運輸
環形DP
還是斷環成鏈的操作
把環拆開,複製一倍,形成一個長度為 \(2n\) 的鏈
那麼就是要求最大的 \(1\le{i,j}\le{2n}\) 且 \({i-j}\le{\dfrac{n}{2}}\) 的 \(i,j\),\(a_i+a_j+i-j\) 的最大值
可以用單調佇列優化,做到 \(O(n)\) 的複雜度#include <map> #include <cmath> #include <queue> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int A = 2e6 + 11; const int B = 1e6 + 11; const int mod = 1e9 + 7; const int inf = 0x3f3f3f3f; inline int read() { char c = getchar(); int x = 0, f = 1; for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1; for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return x * f; } int n, head, tail, len, a[A], q[A], ans; int main() { n = read(); for (int i = 1; i <= n; i++) a[i] = read(), a[i + n] = a[i]; len = n / 2, head = 1, tail = 0; q[++tail] = a[1]; for (int i = 2; i <= n * 2; i++) { while (head <= tail && q[head] < i - len) head++; ans = max(ans, i + a[i] + a[q[head]] - q[head]); while (head <= tail && a[q[tail]] - q[tail] < a[i] - i) tail--; q[++tail] = i; } cout << ans << '\n'; return 0; }