1. 程式人生 > 實用技巧 >題解 P3842 【[TJOI2007]線段】

題解 P3842 【[TJOI2007]線段】

大家寫的都是普通的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;
}