dp好題
阿新 • • 發佈:2020-10-18
1. CF813D
題意:
給一個長度為\(n\)的序列,求兩個不相交的子集長度之和最大是多少,能放入同一子集的條件是首先順序不能變,然後每一個相鄰的要麼相差\(1\)或者相差\(7\)的倍數。 \(n < 5000\)
題解:
\(f[i][j]\) 表示第一序列到了第 \(i\) 位,第二個序列到了第 \(j\) 位,符合條件的長度之和最大.
那麼顯然可以退出 \(O(n^3)\) 方程:
i : 1 ~ n
j : i + 1 ~ n
k : 分兩段。
第一段:1 ~ i,此時判一下a[k]有沒有被j選中,如果沒有在考慮轉移i
第二段:j ~ n,此時就分別轉移i,j就行了
那麼這肯定是過不了的,所以還需要優化。
就是開一個桶記錄相差 \(1\) 的 \(max\)
再開一個桶記錄 \(\%7\) 同餘
程式碼:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <cmath> #define N 5200 #define M 100010 #define ls x << 1 #define rs x << 1 | 1 #define inf 10000000000 #define inc(i) (++ (i)) #define dec(i) (-- (i)) // #define mid ((l + r) >> 1) #define int long long #define XRZ 212370440130137957 #define debug() puts("XRZ TXDY"); #define mem(i, x) memset(i, x, sizeof(i)); #define Next(i, u) for(register int i = head[u]; i ; i = e[i].nxt) #define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout); #define Rep(i, a, b) for(register int i = (a) , i##Limit = (b) ; i <= i##Limit ; inc(i)) #define Dep(i, a, b) for(register int i = (a) , i##Limit = (b) ; i >= i##Limit ; dec(i)) int dx[10] = {1, -1, 0, 0}; int dy[10] = {0, 0, 1, -1}; using namespace std; // const int base = 30; // const int prime = 19260817; inline int read() { register int x = 0, f = 1; register char c = getchar(); while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar(); return x * f; } int pre[M], num[10], n, ans, a[N], f[N][N]; void clean() { mem(num, 0) mem(pre, 0)} signed main() { n = read(); Rep(i, 1, n) a[i] = read(); Rep(i, 0, n) { clean(); Rep(j, 1, i - 1) pre[a[j]] = max(pre[a[j]], f[i][j]), num[a[j] % 7] = max(num[a[j] % 7], f[i][j]); Rep(j, i + 1, n) { f[i][j] = f[i][0] + 1; f[i][j] = max(f[i][j], max(pre[a[j] + 1] + 1, max(pre[a[j] - 1] + 1, num[a[j] % 7] + 1))); f[j][i] = f[i][j]; pre[a[j]] = max(pre[a[j]], f[i][j]), num[a[j] % 7] = max(num[a[j] % 7], f[i][j]); ans = max(ans, f[i][j]); } } printf("%lld", ans); return 0;//int zmy = 666666, zzz = 233333; }
2.CF796E
題意:
有 \(n\) 道題目,有兩個人分別會做某些題目,有 \(p\) 次偷看機會,每次可以偷看某個人最多連續 \(k\) 道題目,求最多偷看幾道題目。
題解:
這題細節比較多,思路比較板。
具體 令\(dp[i][j][L][R]\) 表示當前為第 \(i\) 題,已經偷看了 \(j\) 次,還能向左邊的大神看 \(L\) 道題,向右邊的大神看 \(R\) 道題。
然後就隨便轉移(霧
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <cmath> #define N 1010 #define M 55 #define ls x << 1 #define rs x << 1 | 1 #define inf 10000000000 #define inc(i) (++ (i)) #define dec(i) (-- (i)) // #define mid ((l + r) >> 1) //#define int long long #define XRZ 212370440130137957 #define debug() puts("XRZ TXDY"); #define mem(i, x) memset(i, x, sizeof(i)); #define Next(i, u) for(register int i = head[u]; i ; i = e[i].nxt) #define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout); #define Rep(i, a, b) for(register int i = (a) , i##Limit = (b) ; i <= i##Limit ; inc(i)) #define Dep(i, a, b) for(register int i = (a) , i##Limit = (b) ; i >= i##Limit ; dec(i)) int dx[10] = {1, -1, 0, 0}; int dy[10] = {0, 0, 1, -1}; using namespace std; // const int base = 30; // const int prime = 19260817; inline int read() { register int x = 0, f = 1; register char c = getchar(); while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar(); return x * f; } int n, m, k, ans, a[N], b[N], f[2][N][M][M]; void clean() {memset(f, -0x3f3f3f, sizeof(f));} int main() { n = read(), m = read(), k = read(); int pp = read(); Rep(i, 1, pp) a[read()] = 1; //debug() pp = read(); Rep(i, 1, pp) b[read()] = 1; memset(f, -0x3f3f3f, sizeof(f)); f[0][0][0][0] = 0;//debug() if(m * k >= n * 2) { Rep(i, 1, n) ans += (a[i] | b[i]); printf("%d", ans); return 0;} Rep(i, 1, n) { memset(f[i % 2], -0x3f3f3f, sizeof(f[i % 2])); //debug() Rep(j, 0, m) Rep(L, 0, k) Rep(R, 0, k) { int now = f[(i + 1) % 2][j][L][R]; f[i % 2][j][max(L - 1, 0)][max(R - 1, 0)] = max(f[i % 2][j][max(L - 1, 0)][max(R - 1, 0)], now); if(L) f[i % 2][j][L - 1][max(R - 1, 0)] = max(f[i % 2][j][L - 1][max(R - 1, 0)], now + a[i]); if(R) f[i % 2][j][max(L - 1, 0)][R - 1] = max(f[i % 2][j][max(L - 1, 0)][R - 1], now + b[i]); if(L) f[i % 2][j + 1][L - 1][k - 1] = max(f[i % 2][j + 1][L - 1][k - 1], now + (a[i] | b[i])); if(R) f[i % 2][j + 1][k - 1][R - 1] = max(f[i % 2][j + 1][k - 1][R - 1], now + (a[i] | b[i])); if(L && R) f[i % 2][j][L - 1][R - 1] = max(f[i % 2][j][L - 1][R - 1], now + (a[i] | b[i])); f[i % 2][j + 1][k - 1][max(R - 1, 0)] = max(f[i % 2][j + 1][k - 1][max(R - 1, 0)], now + a[i]); f[i % 2][j + 1][max(L - 1, 0)][k - 1] = max(f[i % 2][j + 1][max(L - 1, 0)][k - 1], now + b[i]); f[i % 2][j + 2][k - 1][k - 1] = max(f[i % 2][j + 2][L - 1][R - 1], now + (a[i] | b[i])); } } Rep(j, 0, m) Rep(L, 0, k) Rep(R, 0, k) ans = max(ans, f[n % 2][j][L][R]); printf("%d", ans); return 0;//int zmy = 666666, zzz = 233333; }