难度
− 317 628 -\frac{317}{628} −628317
看
紫
书
上
有
→
找
到
U
V
A
→
V
J
+
U
V
A
O
J
交
不
上
→
找
到
H
D
U
原
题
看紫书上有\rightarrow找到UVA\rightarrow VJ+UVAOJ交不上\rightarrow找到HDU原题
看紫书上有→找到UVA→VJ+UVAOJ交不上→找到HDU原题
???
题意
- 给定四个堆,每堆的糖果你只能从顶开始拿。
- 给你一个篮子,篮子最多装五个糖果。
- 如果篮子其中有两个糖果编号一样,则你获得一堆糖果,这两个糖果移除篮子。
- 问你:你最多能获得多少堆糖果?
数据范围
每堆大小
n
≤
40
n\le 40
n≤40
糖果种类
≤
20
\le 20
≤20
开始的思路
- 一看:四堆,每堆最多 40 40 40 个,考虑 D P DP DP 的话 状态数 4 0 4 ≈ 2 e 6 40^4\approx2e6 404≈2e6 貌似可行
- 然后假设 d p [ i ] [ j ] [ k ] [ p ] dp[i][j][k][p] dp[i][j][k][p] 表示第一堆、第二堆、第三堆、第四堆拿了 i 、 j 、 k 、 p i、j、k、p i、j、k、p个糖时能获得最多多少对糖果。
- 因为每堆拿的数量一定了,多余的一些没有匹配的在篮子里的糖果也是一定的。
- 我们把他们存入 V [ i ] [ j ] [ k ] [ p ] V[i][j][k][p] V[i][j][k][p] 中。
- 状态转移:对于
(
i
,
j
,
k
,
p
)
(i,j,k,p)
(i,j,k,p)的情况,我们只有四种状态转移过来:
( i − 1 , j , k , p ) 、 ( i , j − 1 , k , p ) 、 ( i , j , k − 1 , p ) 、 ( i , j , k , p − 1 ) (i-1,j,k,p)、(i,j-1,k,p)、(i,j,k-1,p)、(i,j,k,p-1) (i−1,j,k,p)、(i,j−1,k,p)、(i,j,k−1,p)、(i,j,k,p−1) - 转移过来的时候,只要选择一种合法状态转移过来即可,因为能转移的话答案是一定的。
- 如果四种状态都是非法的(无法达到的状态),那么新的状态也无法达到。
然后的思路
- 写完快快乐乐交上去,结果因为 M L E MLE MLE 瞬间嗝屁。
- 内存 O ( k × 4 0 4 ) O(k\times 40^4) O(k×404),这里 k k k 至少也得是 2 2 2吧, 2 × 4 0 4 = 5 e 6 2\times 40^4=5e6 2×404=5e6
- 给定的内存 32768 K = 32768 ∗ 1024 / 8 ( 个 i n t ) = 4 e 6 ( 个 i n t ) 32768K=32768*1024/8(个int)=4e6(个int) 32768K=32768∗1024/8(个int)=4e6(个int),明显超了。
- 考虑到转移只会影响上一层的,我们滚动数组一下!(然后就过了。)
核心代码
时间复杂度:
O
(
k
×
4
0
4
)
O(k\times 40^4)
O(k×404)
空间复杂度:
O
(
k
×
4
0
3
)
O(k\times 40^3)
O(k×403)
这里大约
1
≤
k
≤
5
1\le k\le 5
1≤k≤5
/*
_ __ __ _ _
| | \ \ / / | | (_)
| |__ _ _ \ V /__ _ _ __ | | ___ _
| '_ \| | | | \ // _` | '_ \| | / _ \ |
| |_) | |_| | | | (_| | | | | |___| __/ |
|_.__/ \__, | \_/\__,_|_| |_\_____/\___|_|
__/ |
|___/
*/
const int MAX = 1e6+50;
const int INF = 0x3f3f3f3f;
int aa[50][6];
vector<int>V[3][41][41][41];
int dp[3][41][41][41];
int main()
{
int n;
while(~scanf("%d",&n)){
if(n == 0)break;
for(int i = 1;i <= n;++i){
for(int j = 1;j <= 4;++j){
scanf("%d",&aa[i][j]);
}
}
for(int i = 0;i <= 2;++i)
for(int j = 0;j <= n;++j)
for(int k = 0;k <= n;++k)
for(int p = 0;p <= n;++p){
V[i][j][k][p].clear();
}
int ans = 0;
for(int i = 0;i <= n;++i)
for(int j = 0;j <= n;++j)
for(int k = 0;k <= n;++k)
for(int p = 0;p <= n;++p){
int t = (i-1+3)%3;
V[i%3][j][k][p].clear();
dp[i%3][j][k][p] = 0;
if(i && V[t][j][k][p].size() < 5){
dp[i%3][j][k][p] = dp[t][j][k][p];
bool fd = false;
for(auto it : V[t][j][k][p]){
if(it == aa[i][1])fd = true;
else V[i%3][j][k][p].push_back(it);
}
if(!fd)V[i%3][j][k][p].push_back(aa[i][1]);
else dp[i%3][j][k][p]++;
}else if(j && V[i%3][j-1][k][p].size() < 5){
dp[i%3][j][k][p] = dp[i%3][j-1][k][p];
bool fd = false;
for(auto it : V[i%3][j-1][k][p]){
if(it == aa[j][2])fd = true;
else V[i%3][j][k][p].push_back(it);
}
if(!fd)V[i%3][j][k][p].push_back(aa[j][2]);
else dp[i%3][j][k][p]++;
}else if(k && V[i%3][j][k-1][p].size() < 5){
dp[i%3][j][k][p] = dp[i%3][j][k-1][p];
bool fd = false;
for(auto it : V[i%3][j][k-1][p]){
if(it == aa[k][3])fd = true;
else V[i%3][j][k][p].push_back(it);
}
if(!fd)V[i%3][j][k][p].push_back(aa[k][3]);
else dp[i%3][j][k][p]++;
}else if(p && V[i%3][j][k][p-1].size() < 5){
dp[i%3][j][k][p] = dp[i%3][j][k][p-1];
bool fd = false;
for(auto it : V[i%3][j][k][p-1]){
if(it == aa[p][4])fd = true;
else V[i%3][j][k][p].push_back(it);
}
if(!fd)V[i%3][j][k][p].push_back(aa[p][4]);
else dp[i%3][j][k][p]++;
}else{
if(i || j || k || p)for(int tmp = 1;tmp <= 6;++tmp)V[i%3][j][k][p].push_back(-1);
}
if(V[i%3][j][k][p].size() <= 5){
ans = max(ans,dp[i%3][j][k][p]);
}
}
printf("%d\n",ans);
}
return 0;
}