本节内容主要讲述一些进阶的动态规划
包括轮廓线动态规划,四边形不等式,单调队列优化等等

轮廓线动态规划

POJ2411
POJ2411

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const int maxn = 11 + 1;
llong f[maxn][1 << maxn];
bool inS[1 << maxn];
int N, M;

void init() {
Set(f, 0);
f[0][0] = 1;
}

inline void cal() {
_for(i, 0, 1 << M) {
bool cnt = 0, hasOdd = 0;
_for(k, 0, M) {
if((i >> k) & 1) hasOdd |= cnt, cnt = 0;
else cnt ^= 1;
}
inS[i] = hasOdd | cnt ? 0 : 1;
}
}

void dp() {
_rep(i, 1, N) _for(j, 0, 1 << M) {
f[i][j] = 0;
_for(k, 0, 1 << M) {
if((j & k) == 0 && inS[j | k]) f[i][j] += f[i - 1][k];
}
}
}

int main() {
freopen("input.txt", "r", stdin);
while (cin >> N >> M && N) {
init();
cal();

dp();
cout << f[N][0] << endl;
}
}

状态压缩

POJ1185
POJ1185

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

const int inf = 0x3f3f3f3f;
const int maxn = 100 + 1, maxs = 160;
const int maxm = 10 + 1;
int f[maxn][maxs][maxs];
int fbid[maxn];
int cnt[maxs];
int buf[maxs];
int N, M;
int tot = 0;

void init() {
Set(fbid, 0);
Set(cnt, 0);
Set(buf, 0);
tot = 0;
}

int getone(int x) {
int cnt = 0;
while (x) {
if((x & 1) == 1) cnt++;
x >>= 1;
}
return cnt;
}

bool ok(int x) {
if(x & (x << 1)) return false;
if(x & (x << 2)) return false;
return true;
}

inline void cal() {
tot = 0;
_for(st, 0, 1 << M) if(ok(st)) {
buf[tot] = st;
cnt[tot++] = getone(st);
}
}

void initdp() {
Set(f, -1);
f[0][0][0] = 0;
}

bool valid(int i, int st) {
if(fbid[i] & st) return false;
return true;
}

int dp() {
int ans = 0;
_for(k, 0, tot) if(valid(1, buf[k])) {
f[1][k][0] = cnt[k];
ans = max(ans, f[1][k][0]);
//debug(ans);
}

_rep(i, 2, N) {
_for(j, 0, tot) if(valid(i, buf[j])) {
_for(k, 0, tot) if(valid(i - 1, buf[k]) && (buf[k]&buf[j]) == 0) {
int pre = 0;
_for(l, 0, tot) if(f[i - 1][k][l] != -1 && valid(i - 2, buf[l]) && (buf[l]&buf[j]) == 0) {
pre = max(pre, f[i - 1][k][l]);
}

f[i][j][k] = max(f[i][j][k], pre + cnt[j]);
if(i == N) ans = max(ans, f[i][j][k]);
}
}
}
return ans;
}

int main() {
freopen("input.txt", "r", stdin);
init();

scanf("%d%d", &N, &M);
_rep(i, 1, N) {
char t[maxm];
scanf("%s", t);
//debug(t);
_for(j, 0, M) {
if(t[j] == 'H') {
fbid[i] |= (1 << (M-1-j));
}
}
//debug(fbid[i]);
}
// then dp
cal();
initdp();
printf("%d\n", dp());
}

RMQ倍增算法

RMQ

HDU1806
HDU1806

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

const int maxn = 100000 + 5;
const int maxlog = 20;
int A[maxn];
int N, Q;

class RMQ {
public:
int f[maxn][maxlog];
void init(const vector<int>& A) {
int n = A.size();;
_for(i, 0, n) f[i][0] = A[i];
for(int j = 1; (1<<j) <= n; j++) {
for(int i = 0; i + (1<<j) - 1 < n; i++) {
f[i][j] = max(f[i][j - 1], f[i + (1<<(j-1))][j - 1]);
}
}
}

int query(int L, int R) {
int k = 0;
while ((1<<(k+1)) <= R - L + 1) k++;
return max(f[L][k], f[R-(1<<k)+1][k]);
}
};

int _left[maxn], _right[maxn], idx[maxn];
vector<int> cnt;
// cnt[seg id]

void init() {
Set(_left, 0);
Set(_right, 0);
Set(idx, 0);
cnt.clear();
}

inline void cal(vector<int>& cnt) {
int s = -1;
_rep(i, 0, N) {
if(i == 0 || A[i] > A[i-1]) {
if(i > 0) {
cnt.push_back(i - s);
_for(k, s, i) {
idx[k] = cnt.size() - 1;
_left[k] = s;
_right[k] = i - 1;
}
}
s = i;
}
}
}

int main() {
freopen("input.txt", "r", stdin);
while (scanf("%d%d", &N, &Q) == 2) {
_for(i, 0, N) scanf("%d", &A[i]);
A[N] = A[N - 1] + 1;
// special for RMQ

init();
cal(cnt);

// then rmq
RMQ rmq;
rmq.init(cnt);

// then query
while (Q--) {
int L, R, ans;
scanf("%d%d", &L, &R);
L--, R--;

if(idx[L] == idx[R]) ans = R - L + 1;
else {
ans = max(_right[L] - L + 1, R - _left[R] + 1);
if(idx[L] + 1 < idx[R]) ans = max(ans, rmq.query(idx[L] + 1, idx[R] - 1));
}
printf("%d\n", ans);
}
}
}

复习,双向链表邻值查找

DoubleLink
doubleLink

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

const int maxn = 100000 + 5;
int N;

class Node {
public:
int x, k, pre, nxt;
bool operator< (const Node& rhs) const {
return x < rhs.x;
}
};
Node A[maxn];
int B[maxn];

class Ans {
public:
int x, k;
};
Ans ans[maxn];

int main() {
freopen("input.txt", "r", stdin);
scanf("%d", &N);
_rep(i, 1, N) {
scanf("%d", &A[i].x);
A[i].k = i;
}

sort(A + 1, A + 1 + N);
_rep(i, 1, N) {
B[A[i].k] = i;
A[i].pre = i - 1;
A[i].nxt = i + 1;
}

int l = 1, r = N;
_forDown(i, N, 1) {
if(B[i] == r) {
ans[i].x = A[r].x - A[A[r].pre].x;
ans[i].k = A[A[r].pre].k;
r = A[r].pre;
}
else if(B[i] == l) {
ans[i].x = A[A[l].nxt].x - A[l].x;
ans[i].k = A[A[l].nxt].k;
l = A[l].nxt;
}
else {
ans[i].x = A[A[B[i]].nxt].x - A[B[i]].x;
ans[i].k = A[A[B[i]].nxt].k;
if(A[B[i]].x - A[A[B[i]].pre].x <= ans[i].x) {
ans[i].x = A[B[i]].x - A[A[B[i]].pre].x;
ans[i].k = A[A[B[i]].pre].k;
}
}
A[A[B[i]].pre].nxt = A[B[i]].nxt;
A[A[B[i]].nxt].pre = A[B[i]].pre;
}
_rep(i, 2, N) printf("%d %d\n", ans[i].x, ans[i].k);
}

倍增优化dp

NOIP2012
NOIP2012-01
NOIP2012-02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#define MPR(a, b) make_pair(a, b)

const int maxn = 100000 + 5, inf = 0x3f3f3f3f;
const int maxlog = 20;
int N, lgN, m;
int h[maxn], x[maxn], s[maxn];
int ga[maxn], gb[maxn];
int f[maxlog][maxn][2], da[maxlog][maxn][2], db[maxlog][maxn][2];
int la = 0, lb = 0;

multiset<pair<int, int> > st;
typedef multiset<pair<int, int> >::iterator SII;
SII it1, it2, it3, it4, it;

void init() {
st.clear();
st.insert(make_pair(inf, 0));
st.insert(make_pair(-inf, 0));
st.insert(make_pair(inf, 0));
st.insert(make_pair(-inf, 0));
h[0] = 0;
Set(ga, 0);
Set(gb, 0);
la = lb = 0;
}

// pair(value, id)
inline void calg() {
for(int i = N; i; i--) {
st.insert(MPR(h[i], i));
it = st.find(MPR(h[i], i));

it1 = (++it);
it2 = (++it);
it3 = (--(--(--it)));
it4 = (--it);

int a = (*it3).first != -inf ? h[i] - (*it3).first : inf;
int b = (*it1).first != inf ? (*it1).first - h[i] : inf;
if(a <= b) {
// choose it3 as gb[]
gb[i] = (*it3).second;
// (it1, it4) cmp
a = (*it4).first != -inf ? h[i] - (*it4).first : inf;
ga[i] = (a <= b ? (*it4).second : (*it1).second);
} else {
// choose it1 as gb[]
gb[i] = (*it1).second;
b = (*it2).first != inf ? (*it2).first - h[i] : inf;
ga[i] = (a <= b ? (*it3).second : (*it2).second);
}
}
}

void calf() {
_rep(i, 1, N) {
f[0][i][0] = ga[i];
f[0][i][1] = gb[i];
}
_rep(i, 1, N) {
f[1][i][0] = f[0][ f[0][i][0] ][1];
f[1][i][1] = f[0][ f[0][i][1] ][0];
}
_for(i, 2, lgN) {
_rep(j, 1, N) {
f[i][j][0] = f[i-1][ f[i-1][j][0] ][0];
f[i][j][1] = f[i-1][ f[i-1][j][1] ][1];
}
}
}

void cald() {
_rep(i, 1, N) {
da[0][i][0] = abs(h[i] - h[ga[i]]);
db[0][i][1] = abs(h[i] - h[gb[i]]);
da[0][i][1] = db[0][i][0] = 0;
}
_rep(i, 1, N) {
da[1][i][0] = da[0][i][0];
db[1][i][1] = db[0][i][1];

da[1][i][1] = da[0][ f[0][i][1] ][0];
db[1][i][0] = db[0][ f[0][i][0] ][1];
}

_for(i, 2, lgN) _rep(j, 1, N) _for(k, 0, 2) {
da[i][j][k] = da[i-1][j][k] + da[i-1][ f[i-1][j][k] ][k];
db[i][j][k] = db[i-1][j][k] + db[i-1][ f[i-1][j][k] ][k];
}
}

void calS(int S, int X) {
// always start from A, A first
la = lb = 0;
int p = S;
_forDown(i, lgN, 0) {
if(f[i][p][0] && la + lb + da[i][p][0] + db[i][p][0] <= X) {
la += da[i][p][0];
lb += db[i][p][0];
p = f[i][p][0];
}
}
}

void solve1() {
calS(1, x[0]);
// ans1 (pID, heightValue)
//double ans1[2] = {1, (lb ? (double)la / lb : inf)};
pair<int, double> ans1 = MPR(1, (double)(lb ? (double)la / lb : inf));
_rep(i, 2, N) {
calS(i, x[0]);
if((double)la / lb < ans1.second || ((double)la / lb == ans1.second && h[i] > h[ans1.first])) {
ans1 = MPR(i, (double)la / lb);
}
}
cout << ans1.first << endl;
}

void solve2() {
_rep(i, 1, m) {
calS(s[i], x[i]);
//cout << s[i] << " " << x[i] << endl;
printf("%d %d\n", la, lb);
}
}

int main() {
freopen("input.txt", "r", stdin);
cin >> N;
lgN = log(N) / log(2.0);
// debug(lgN);
_rep(i, 1, N) scanf("%d", &h[i]);
cin >> x[0] >> m;
_rep(i, 1, m) scanf("%d%d", &s[i], &x[i]);

// input finished, then solve
init();
calg();
calf();
cald();
solve1();
solve2();
}

串匹配和倍增

Acwing294
CH5702

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
const int maxl = 100 + 5, maxn = 1000000 + 5;
const int maxlog = 30;

llong f[maxl][maxlog + 2];
string s1, s2;
int n1, n2;

void init() {
Set(f, 0);
}

inline bool cal() {
_for(i, 0, s1.size()) {
int p = i;
f[i][0] = 0;
_for(j, 0, s2.size()) {
int cnt = 0;

// then try to find s1[p] matched s2[j]
while (s1[p] != s2[j]) {
p = (p + 1) % (int)s1.size();
if(++cnt >= s1.size()) {
cout << 0 << endl;
return false;
}
}

p = (p + 1) % (int)s1.size();
f[i][0] += cnt + 1;
}
}
return true;
}

void dp() {
_rep(j, 1, maxlog) _for(i, 0, s1.size()) {
f[i][j] = f[i][j - 1] + f[(i + f[i][j-1] ) % s1.size()][j - 1];
}
}


int main() {
freopen("input.txt", "r", stdin);
while (cin >> s2 >> n2 >> s1 >> n1) {
init();
// debug(s2);
if(!cal()) continue;

dp();

llong m = 0;
_for(st, 0, s1.size()) {
llong x = st, ans = 0;

// then connect 2^k
_forDown(k, maxlog, 0) {
if(x + f[x % s1.size()][k] <= n1 * s1.size()) {
x += f[x % s1.size()][k];
ans += (1 << k);
}
}

m = max(m, ans);
}

cout << m / n2 << endl;
}
}