Description
Input
Output
Sample Input
输入1:
10 10 6
3 9
9 9
1 2
1 3
1 2
1 1
2 1
2 1
1 6
2 2
1 2 7
5 1 5
6 3 5
7 5 8
8 7 9
9 1 3
输入2:
10 10 4
1 2
3 1
2 2
1 8
1 8
3 2
2 1
2 1
2 2
1 2
1 0 2
6 7 9
9 1 4
3 8 10
Sample Output
输出1:
1
6
输出2:
0
3
Data Constraint
题解
70pts:
不难想到此题使用DP 设
f
i
,
j
f_{i,j}
fi,j表示到第i列第j行的答案,则对于一般的j状态转移方程为
f
i
,
j
=
m
i
n
(
f
i
−
1
,
j
+
y
i
−
1
,
m
i
n
j
−
k
∗
x
i
−
1
>
0
,
k
>
0
(
f
i
−
1
,
j
−
k
∗
x
i
−
1
)
+
k
)
f_{i,j} = min(f_{i - 1, j + y_{i - 1}}, min_{j - k * x_{i - 1} > 0,k>0} (f_{i - 1, j - k * x_{i - 1}}) + k)
fi,j=min(fi−1,j+yi−1,minj−k∗xi−1>0,k>0(fi−1,j−k∗xi−1)+k)
然后特判下边界就行~
复杂度
O
(
n
m
2
)
O(nm^2)
O(nm2)
100pts
注意到上式中的
m
i
n
j
−
k
∗
x
i
−
1
>
0
,
k
>
0
(
f
i
−
1
,
j
−
k
∗
x
i
−
1
)
min_{j - k * x_{i - 1} > 0,k>0} (f_{i - 1, j - k * x_{i - 1}})
minj−k∗xi−1>0,k>0(fi−1,j−k∗xi−1)中
m
i
n
j
−
k
∗
x
i
−
1
>
0
,
k
>
1
(
f
i
−
1
,
j
−
k
∗
x
i
−
1
)
min_{j - k * x_{i - 1} > 0 , k > 1} (f_{i - 1, j - k * x_{i - 1}})
minj−k∗xi−1>0,k>1(fi−1,j−k∗xi−1)都被计算过,直接拿来用就行了,于是方程化为
f
i
,
j
=
m
i
n
(
f
i
−
1
,
j
−
x
i
−
1
,
f
i
,
j
−
x
i
−
1
)
+
1
f_{i,j} = min(f_{i - 1, j - x_{i - 1}}, f_{i, j - x_{i - 1}}) + 1
fi,j=min(fi−1,j−xi−1,fi,j−xi−1)+1 ,每做完一列再做一次
f
i
,
j
=
m
i
n
(
f
i
,
j
,
f
i
−
1
,
j
+
y
i
−
1
)
f_{i,j} = min(f_{i, j}, f_{i - 1, j + y_{i - 1}})
fi,j=min(fi,j,fi−1,j+yi−1),于是复杂度化为
O
(
n
m
)
O(nm)
O(nm)可以通过本题。
具体实现要注意下细节,我的代码可能打的不是太优美,但是可以拿来参考
Code
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 10100;
const int M = 2000;
const int inf = 9999999;
int n, m, k, x[N], y[N], l[N], h[N], ans = 9999999, f[N][M], cnt;
inline int read() {
int res = 0;
char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar());
for(; ch >= '0' && ch <= '9'; res = res * 10 + ch - '0', ch = getchar());
return res;
}
int main() {
n = read(), m = read(), k = read();
for(int i = 1; i <= n; ++i) {
x[i] = read(),
y[i] = read(),
l[i] = m + 1,
h[i] = 0;
}
l[n + 1] = m + 1, h[n + 1] = 0;
for(int i = 1; i <= k; ++i) {
int p = read(), lo = read(), hi = read();
h[p + 1] = lo,
l[p + 1] = hi;
}
for(int i = 1; i <= n + 1; ++i)
for(int j = 0; j < M; ++j)
f[i][j] = inf;
for(int i = h[1] + 1; i < l[1]; ++i)
f[1][i] = 0;
for(int i = 2; i <= n + 1; ++i) {
bool flag = false;
for(int j = x[i - 1] + 1; j < m; ++j)
f[i][j] = min(f[i - 1][j - x[i - 1]], f[i][j - x[i - 1]]) + 1;
for(int j = 1; j <= m; ++j)
f[i][m] = min(f[i][m], f[i - 1][j] + max(1, (m - j + x[i - 1] - 1) / x[i - 1]));
for(int j = 1; j < m; ++j) {
f[i][j] = min(f[i][j], f[i - 1][j + y[i - 1]]);
if(f[i][j] == inf + 1) --f[i][j];
}
if(f[i][m] > inf) f[i][m] = inf;
for(int j = 0; j <= h[i]; ++j) f[i][j] = inf;
for(int j = l[i]; j <= m; ++j) f[i][j] = inf;
for(int j = h[i] + 1; j < l[i]; ++j)
if(f[i][j] != inf) flag = true;
if(!flag) {
printf("0\n%d\n",cnt);
return 0;
}
if(l[i] != m + 1 || h[i] != 0) ++cnt;
}
for(int i = h[n + 1] + 1; i < l[n + 1]; ++i)
ans = min(ans, f[n + 1][i]);
printf("1\n%d\n",ans);
return 0;
}