感受
变
菜
了
,
居
然
没
有
想
出
来
变菜了,居然没有想出来
变菜了,居然没有想出来
思路
n
3
暴
力
D
p
应
该
很
容
易
想
的
,
这
里
不
再
赘
述
n^3暴力Dp应该很容易想的,这里不再赘述
n3暴力Dp应该很容易想的,这里不再赘述
设
f
[
i
]
[
j
]
为
前
i
张
邮
票
使
用
不
超
过
j
个
集
合
获
得
的
最
大
种
类
数
设f[i][j]为前i张邮票使用不超过j个集合获得的最大种类数
设f[i][j]为前i张邮票使用不超过j个集合获得的最大种类数
状
态
转
移
分
析
:
状态转移分析:
状态转移分析:
f
[
i
]
[
j
]
如
何
由
f
[
1..
i
−
1
]
[
]
更
新
呢
?
f[i][j]如何由f[1..i-1][]更新呢?
f[i][j]如何由f[1..i−1][]更新呢?
两
者
差
距
在
于
现
在
多
了
第
i
种
邮
票
!
两者差距在于现在多了第i种邮票!
两者差距在于现在多了第i种邮票!
(
1
)
如
果
当
前
不
使
用
任
何
集
合
(1)如果当前不使用任何集合
(1)如果当前不使用任何集合
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
f[i][j] = f[i-1][j]
f[i][j]=f[i−1][j]
即
不
管
现
在
有
没
有
第
i
种
邮
票
,
我
都
不
选
它
,
所
以
两
者
结
果
相
同
即不管现在有没有第i种邮票,我都不选它,所以两者结果\\相同
即不管现在有没有第i种邮票,我都不选它,所以两者结果相同
(
2
)
如
果
当
前
使
用
一
个
集
合
,
即
作
S
(2)如果当前使用一个集合,即作S
(2)如果当前使用一个集合,即作S
a
.
如
果
S
的
左
端
点
大
于
i
,
对
f
[
i
]
[
j
]
结
果
肯
定
无
影
响
a.如果S的左端点大于i,对f[i][j]结果肯定无影响
a.如果S的左端点大于i,对f[i][j]结果肯定无影响
因
为
,
此
时
大
于
i
的
邮
票
还
没
出
现
因为,此时大于i的邮票还没出现
因为,此时大于i的邮票还没出现
b
.
如
果
S
的
右
端
点
小
与
i
,
此
更
新
答
案
必
<
=
f
[
i
−
1
]
[
j
]
b.如果S的右端点小与i,此更新答案必<=f[i-1][j]
b.如果S的右端点小与i,此更新答案必<=f[i−1][j]
为
什
么
呢
?
因
为
现
在
的
选
择
并
没
有
涉
及
到
第
i
种
邮
票
,
所
以
用
f
[
i
−
1
]
[
j
]
答
案
更
优
为什么呢?因为现在的选择并没有涉及到第i种邮票,所以\\用f[i-1][j]答案更优
为什么呢?因为现在的选择并没有涉及到第i种邮票,所以用f[i−1][j]答案更优
c
.
除
了
a
与
b
情
况
,
那
么
S
的
左
端
点
<
=
i
,
S
的
右
端
点
>
=
i
c.除了a与b情况,那么S的左端点<=i,S的右端点>=i
c.除了a与b情况,那么S的左端点<=i,S的右端点>=i
也
就
是
从
众
多
包
括
i
的
集
合
中
选
择
一
个
最
优
的
,
其
实
看
下
图
即
可
知
道
最
优
的
是
左
端
点
距
离
i
最
远
且
与
i
有
交
集
的
也就是从众多包括i的集合中选择一个最优的,其实看下图\\即可知道最优的是左端点距离i最远且与i有交集的
也就是从众多包括i的集合中选择一个最优的,其实看下图即可知道最优的是左端点距离i最远且与i有交集的
对
于
此
情
况
,
用
d
p
[
m
i
n
l
−
1
]
[
j
−
1
]
+
i
−
m
i
n
l
+
1
更
新
即
可
对于此情况,用dp[minl - 1][j-1]+i-minl+1更新即可
对于此情况,用dp[minl−1][j−1]+i−minl+1更新即可
证
毕
!
是
不
是
很
简
单
,
我
居
然
想
了
那
么
久
!
证毕!是不是很简单,我居然想了那么久!
证毕!是不是很简单,我居然想了那么久!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e3 + 10;
int f[maxn][maxn];
int lef[maxn], l, r;
int n, m, k;
int main(){
int t, kase = 0;
scanf("%d", &t);
while(t--){
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; i++) lef[i] = n + 1;
for(int i = 1; i <= m; i++){
scanf("%d%d", &l, &r);
for(int j = l; j <= r; j++){
lef[j] = min(lef[j], l);
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
f[i][j] = f[i - 1][j];
if(lef[i] <= i){
f[i][j] = max(f[i][j], f[lef[i] - 1][j - 1] + i - lef[i] + 1);
}
}
}
printf("Case #%d: %d\n", ++kase, f[n][k]);
}
return 0;
}