bzoj1028

1028: [JSOI2007]麻将

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 1337  Solved: 601
[Submit][Status][Discuss]

Description

麻将是中国传统的娱乐工具之一。麻将牌的牌可以分为字牌(共有东、南、西、北、中、发、白七种)和序数牌(分为条子、饼子、万子三种花色,每种花色各有一到九的九种牌),每种牌各四张。在麻将中,通常情况下一组和了的牌(即完成的牌)由十四张牌组成。十四张牌中的两张组成对子(即完全相同的两张牌),剩余的十二张组成三张一组的四组,每一组须为顺子(即同花色且序数相连的序数牌,例如条子的三、四、五)或者是刻子(即完全相同的三张牌)。一组听牌的牌是指一组十三张牌,且再加上某一张牌就可以组成和牌。那一张加上的牌可以称为等待牌。  在这里,我们考虑一种特殊的麻将。在这种特殊的麻将里,没有字牌,花色也只有一种。但是,序数不被限制在一到九的范围内,而是在1到n的范围内。同时,也没有每一种牌四张的限制。一组和了的牌由3m + 2张牌组成,其中两张组成对子,其余3m张组成三张一组的m组,每组须为顺子或刻子。现给出一组3m + 1张的牌,要求判断该组牌是否为听牌(即还差一张就可以和牌)。如果是的话,输出所有可能的等待牌。

Input

包含两行。第一行包含两个由空格隔开整数n, m (9<=n<=400, 4<=m<=1000)。第二行包含3m + 1个由空格隔开整数,每个数均在范围1到n之内。这些数代表要求判断听牌的牌的序数。

Output

输出为一行。如果该组牌为听牌,则输出所有的可能的等待牌的序数,数字之间用一个空格隔开。所有的序数必须按从小到大的顺序输出。如果该组牌不是听牌,则输出"NO"。

Sample Input

9 4
1 1 2 2 3 3 5 5 5 7 8 8 8

Sample Output

6 7 9

HINT

Source

题意:很好懂,前面麻将的介绍基本不用看

精简后的题意

刻子(即完全相同的三张牌     顺子(序数相连的牌,例如三、四、五)           对子(即完全相同的两张牌

序数在1到n的范围内。每一种牌张数无限制。

一组和牌由3m + 2张牌组成,其中两张组成对子,其余3m张组成三张一组的m组,每组须为顺子或刻子。

现给出一组3m + 1张的牌,要求判断该组牌是否为听牌(即还差一张就可以和牌)。如果是的话,输出所有可能的等待牌。

分析:首先看到 n<=400

那么我们会想到的是枚举要加进哪张牌(毕竟要输出的是每一种方案而不是方案数)

那加进之后如何检验。。。。。

我们这样想问题   ->   数字为i的牌只能与 i+1, i+2组成顺子,而不考虑与i-1,i-2组成顺子(即规定一个方向,以免重复和为了下面叙述方便)

那么数字为n-1,n的牌一定要是若干个刻子(在抽走了组成了顺子的牌之后)

那么显然至少有(a[n]%3)个顺子

若顺子的个数大于等于3,即3*k+x个i,i+1,i+2这样个顺子,那么可以当成k个i的刻子和k个i+1的刻子和k个i+2的刻子以及x个顺子(x<3)

所以可以证明倒着枚举数字,优先安排刻子的,其次安排顺子的贪心顺序是正确的

当然正着枚举也是一样的道理

听说这题有dp做法,我得好好想想,不过在网上找不到

这是倒着枚举的代码,其实正着枚举要简单写(其实两代码一样)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <deque>
 6 #include <vector>
 7 #include <queue>
 8 #include <iostream>
 9 #include <algorithm>
10 #include <map>
11 #include <set>
12 #include <ctime>
13 using namespace std;
14 typedef long long LL;
15 typedef double DB;
16 #define For(i, s, t) for(int i = (s); i <= (t); i++)
17 #define Ford(i, s, t) for(int i = (s); i >= (t); i--)
18 #define Rep(i, t) for(int i = (0); i < (t); i++)
19 #define Repn(i, t) for(int i = ((t)-1); i >= (0); i--)
20 #define rep(i, x, t) for(int i = (x); i < (t); i++)
21 #define MIT (2147483647)
22 #define INF (1000000001)
23 #define MLL (1000000000000000001LL)
24 #define sz(x) ((int) (x).size())
25 #define clr(x, y) memset(x, y, sizeof(x))
26 #define puf push_front
27 #define pub push_back
28 #define pof pop_front
29 #define pob pop_back
30 #define ft first
31 #define sd second
32 #define mk make_pair
33 inline void SetIO(string Name) {
34     string Input = Name+".in",
35     Output = Name+".out";
36     freopen(Input.c_str(), "r", stdin),
37     freopen(Output.c_str(), "w", stdout);
38 }
39
40 const int N = 410;
41 int n, m, Arr[N];
42 int Ans[N], Tot;
43
44 inline void Input() {
45     scanf("%d%d", &n, &m);
46     For(i, 1, 3*m+1) {
47         int x;
48         scanf("%d", &x);
49         Arr[x]++;
50     }
51 }
52
53 int Tmp[N];
54 inline bool Check(int x) {
55     For(i, 1, n) {
56         For(j, 1, n) Tmp[j] = Arr[j];
57         Tmp[x]++;
58         Tmp[i] -= 2;
59         if(Tmp[i] < 0) continue;
60
61         bool flag = 1;
62         Ford(j, n, 3) {
63             if(Tmp[j] < 0) {
64                 flag = 0;
65                 break;
66             }
67             if(!Tmp[j]) continue;
68             Tmp[j] %= 3;
69             Tmp[j-1] -= Tmp[j];
70             Tmp[j-2] -= Tmp[j];
71             Tmp[j] = 0;
72         }
73         Tmp[1] %= 3, Tmp[2] %= 3;
74         if(Tmp[1] || Tmp[2]) flag = 0;
75
76         if(flag)  return 1;
77     }
78     return 0;
79 }
80
81 inline void Solve() {
82     For(i, 1, n)
83         if(Check(i)) Ans[++Tot] = i;
84
85     if(!Tot) puts("NO");
86     else {
87         For(i, 1, Tot-1) printf("%d ", Ans[i]);
88         printf("%d\n", Ans[Tot]);
89     }
90 }
91
92 int main() {
93     #ifndef ONLINE_JUDGE
94     SetIO("1028");
95     #endif
96     Input();
97     Solve();
98     return 0;
99 }

这是正着枚举

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <deque>
 6 #include <vector>
 7 #include <queue>
 8 #include <iostream>
 9 #include <algorithm>
10 #include <map>
11 #include <set>
12 #include <ctime>
13 using namespace std;
14 typedef long long LL;
15 typedef double DB;
16 #define For(i, s, t) for(int i = (s); i <= (t); i++)
17 #define Ford(i, s, t) for(int i = (s); i >= (t); i--)
18 #define Rep(i, t) for(int i = (0); i < (t); i++)
19 #define Repn(i, t) for(int i = ((t)-1); i >= (0); i--)
20 #define rep(i, x, t) for(int i = (x); i < (t); i++)
21 #define MIT (2147483647)
22 #define INF (1000000001)
23 #define MLL (1000000000000000001LL)
24 #define sz(x) ((int) (x).size())
25 #define clr(x, y) memset(x, y, sizeof(x))
26 #define puf push_front
27 #define pub push_back
28 #define pof pop_front
29 #define pob pop_back
30 #define ft first
31 #define sd second
32 #define mk make_pair
33 inline void SetIO(string Name) {
34     string Input = Name+".in",
35     Output = Name+".out";
36     freopen(Input.c_str(), "r", stdin),
37     freopen(Output.c_str(), "w", stdout);
38 }
39
40 const int N = 410;
41 int n, m, Arr[N];
42 int Ans[N], Tot;
43
44 inline void Input() {
45     scanf("%d%d", &n, &m);
46     For(i, 1, 3*m+1) {
47         int x;
48         scanf("%d", &x);
49         Arr[x]++;
50     }
51 }
52
53 int Tmp[N];
54 inline bool Check(int x) {
55     For(i, 1, n) {
56         For(j, 1, n+2) Tmp[j] = Arr[j];
57         Tmp[x]++;
58         Tmp[i] -= 2;
59         if(Tmp[i] < 0) continue;
60
61         bool flag = 1;
62         For(j, 1, n+2) {
63             if(Tmp[j] < 0) {
64                 flag = 0;
65                 break;
66             }
67             if(!Tmp[j]) continue;
68             Tmp[j] %= 3;
69             Tmp[j+1] -= Tmp[j];
70             Tmp[j+2] -= Tmp[j];
71             Tmp[j] = 0;
72         }
73         if(flag)  return 1;
74     }
75     return 0;
76 }
77
78 inline void Solve() {
79     For(i, 1, n)
80         if(Check(i)) Ans[++Tot] = i;
81
82     if(!Tot) puts("NO");
83     else {
84         For(i, 1, Tot-1) printf("%d ", Ans[i]);
85         printf("%d\n", Ans[Tot]);
86     }
87 }
88
89 int main() {
90     #ifndef ONLINE_JUDGE
91     SetIO("1028");
92     #endif
93     Input();
94     Solve();
95     return 0;
96 }

时间: 2024-08-07 22:28:20

bzoj1028的相关文章

【BZOJ1028】【JSOI2007】麻将 暴力

转载请注明出处谢谢:http://blog.csdn.net/vmurder/article/details/42921985 题目大意: 给你一副牌,问是否是听牌(即再加一张牌能"胡"),如果是,输出摸到哪些牌能胡,不是输出"NO" 胡牌规则: 首先需要有两个相同数字的牌被消掉,然后可以将三张相同的牌消掉,也可以将三张连续标号的牌消掉,消没即胡. 比如 22 444555 789就是胡牌. 题解: 暴力枚举再摸到哪张牌就能胡, 然后暴力消牌. 代码: #inclu

bzoj千题计划118:bzoj1028: [JSOI2007]麻将

http://www.lydsy.com/JudgeOnline/problem.php?id=1028 枚举等待牌 枚举对是哪个 判断 #include<cstdio> #include<iostream> using namespace std; int sum[405],a[405]; int ans[405],tot; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar();

[bzoj1028] [JSOI2007]麻将

Description 麻将是中国传统的娱乐工具之一.麻将牌的牌可以分为字牌(共有东.南.西.北.中.发.白七种)和序数牌(分为条子.饼子.万子三种花色,每种花色各有一到九的九种牌),每种牌各四张.在麻将中,通常情况下一组和了的牌(即完成的牌)由十四张牌组成.十四张牌中的两张组成对子(即完全相同的两张牌),剩余的十二张组成三张一组的四组,每一组须为顺子(即同花色且序数相连的序数牌,例如条子的三.四.五)或者是刻子(即完全相同的三张牌).一组听牌的牌是指一组十三张牌,且再加上某一张牌就可以组成和牌

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

[转载]hzwer的bzoj题单

counter: 664BZOJ1601 BZOJ1003 BZOJ1002 BZOJ1192 BZOJ1303 BZOJ1270 BZOJ3039 BZOJ1191 BZOJ1059 BZOJ1202 BZOJ1051 BZOJ1001 BZOJ1588 BZOJ1208 BZOJ1491 BZOJ1084 BZOJ1295 BZOJ3109 BZOJ1085 BZOJ1041 BZOJ1087 BZOJ3038 BZOJ1821 BZOJ1076 BZOJ2321 BZOJ1934 BZOJ