題解 P3842 【[TJOI2007]線段】
阿新 • • 發佈:2020-10-18
大家寫的都是普通的dp
我來寫一發滾動dp
何為滾動dp?
就是在轉移的時候不斷利用無用的空間,來避免 \(MLE\) 雖然這裡沒有必要
\(f[i][0]\) 表示走完第i行且停在第i行的左端點最少用的步數
\(f[i][1]\) 表示走完第i行且停在第i行的右端點最少用的步數
那麼遞推方程很好推:
f[i][0] = min(f[i-1][0] + abs(l[i-1] - r[i]), f[i-1][1] + abs(r[i-1] - r[i])) + r[i] - l[i] + 1, f[i][1] = min(f[i-1][0] + abs(l[i-1] - l[i]), f[i-1][1] + abs(r[i-1] - l[i])) + r[i] - l[i] + 1;
這時候你可以發現,當前的狀態只與 \(f[i - 1][0/1]\) 有關。
所以可以得到以下程式碼 :
f[i % 2][1] = min(f[i % 2 ^ 1][0] + abs(L[i % 2] - L[i % 2 ^ 1]), f[i % 2 ^ 1][1] + abs(R[i % 2 ^ 1] - L[i % 2])) + 1 + R[i % 2] - L[i % 2]; f[i % 2][0] = min(f[i % 2 ^ 1][0] + abs(R[i % 2] - L[i % 2 ^ 1]), f[i % 2 ^ 1][1] + abs(R[i % 2 ^ 1] - R[i % 2])) + 1 + R[i % 2] - L[i % 2];
完整程式碼:
#include <algorithm> #include <iostream> #include <cstdio> #include <cstring> #include <string> #include <cmath> #define N 5010 #define M 1000010 #define ls x << 1 #define rs x << 1 | 1 #define inf 0x3f3f3f3f #define inc(i) (++ (i)) #define dec(i) (-- (i)) #define mid ((l + r) >> 1) #define int long long //#define ll long long #define XRZ 19260817 #define pai acos(-1) #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)) using namespace std; 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; } inline int read_plus() { register int res = 0, ch = getchar(); while(!isdigit(ch) and ch != EOF) ch = getchar(); while(isdigit(ch)) res = ((res << 3) + (res << 1) + (ch - '0')) % XRZ, ch = getchar(); return res; } int dx[10] = {0, 1, 1, 2, 2, -1, -1, -2, -2}; int dy[10] = {0, 2, -2, 1, -1, 2, -2, 1, -1}; int exgcd(int a, int b, int &x, int &y) { if(b == 0) { x = 1, y = 0; return a;} int now = exgcd(b, a % b, x, y); int yy = x; x = y, y = yy - a / b * y; return now; } int n, L[2], R[2], f[2][2]; signed main() { n = read(), L[1] = read(), R[1] = read(), f[1][0] = R[1] * 2 - L[1] - 1, f[1][1] = R[1] - 1; Rep(i, 2, n) { L[i % 2] = read(), R[i % 2] = read(); f[i % 2][1] = min(f[i % 2 ^ 1][0] + abs(L[i % 2] - L[i % 2 ^ 1]), f[i % 2 ^ 1][1] + abs(R[i % 2 ^ 1] - L[i % 2])) + 1 + R[i % 2] - L[i % 2]; f[i % 2][0] = min(f[i % 2 ^ 1][0] + abs(R[i % 2] - L[i % 2 ^ 1]), f[i % 2 ^ 1][1] + abs(R[i % 2 ^ 1] - R[i % 2])) + 1 + R[i % 2] - L[i % 2]; // printf("1 : %d %d\n", f[i % 2][0], f[i % 2][1]); } printf("%d", min(f[n % 2][0] + n - L[n % 2], f[n % 2][1] + n - R[n % 2])); return 0; }