斗地主题
题目链接:ybtoj高效进阶 21187
题目大意
打斗地主,对面只剩一张大鬼,到你出牌。
你不会有小鬼,然后问你你是否可以把牌都出掉。
思路
我们发现有可能会输的只有单牌。
那我们就没有必要出三个,炸这种(耍帅)没用的招,而是出三带一,四带二。
那我们就可以这样看,如果一张牌只有一个,那就是 1 1 1 费,如果有两个就是 0 0 0 费,三个就是 − 1 -1 −1 费,四个就是 − 2 -2 −2 费。我们就是要费小于等于 0 0 0。
但是还有一个东西叫做顺子。
那你发现,你一张牌顺子了就少了一费,两张三张四张都是会多一费。
那你就相当于要找若干个区间,每个区间长度至少为 5 5 5,且框起来的数有最小费用。
然后 DP 一下就有了,这时候重新看费用就可以了。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n, a[21], bef, f[21];
int num[21], g[21];
char s[5];
int get_card() {
scanf("%s", s + 1);
int m = strlen(s + 1);
if (m == 1) {
if (s[1] == 'A') return 13;
if (s[1] == 'K') return 12;
if (s[1] == 'Q') return 11;
if (s[1] == 'J') return 10;
return s[1] - '0' - 1;
}
else {
return 9;
}
}
int main() {
// freopen("landlords.in", "r", stdin);
// freopen("landlords.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
a[i] = get_card();
num[a[i]]++;
}
for (int i = 1; i <= 13; i++) {
if (num[i] == 1) bef++, g[i] = 1;
else if (num[i] == 2) g[i] = -1;
else if (num[i] == 3) bef--, g[i] = -1;
else if (num[i] == 4) bef -= 2, g[i] = -1;
else g[i] = -1e7;
}
if (bef <= 1) {
printf("Yes");
return 0;
}
for (int i = 1; i <= 13; i++) g[i] += g[i - 1];
for (int i = 6; i <= 13; i++) {
f[i] = f[i - 1];
for (int j = 5; j < i; j++) {
f[i] = max(f[i], f[i - j] + g[i] - g[i - j]);
}
}
if (bef - f[13] <= 1) {
printf("Yes");
}
else {
printf("No");
}
return 0;
}