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做法,我得好好想想,不过在网上找不到

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

 #include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <ctime>
using namespace std;
typedef long long LL;
typedef double DB;
#define For(i, s, t) for(int i = (s); i <= (t); i++)
#define Ford(i, s, t) for(int i = (s); i >= (t); i--)
#define Rep(i, t) for(int i = (0); i < (t); i++)
#define Repn(i, t) for(int i = ((t)-1); i >= (0); i--)
#define rep(i, x, t) for(int i = (x); i < (t); i++)
#define MIT (2147483647)
#define INF (1000000001)
#define MLL (1000000000000000001LL)
#define sz(x) ((int) (x).size())
#define clr(x, y) memset(x, y, sizeof(x))
#define puf push_front
#define pub push_back
#define pof pop_front
#define pob pop_back
#define ft first
#define sd second
#define mk make_pair
inline void SetIO(string Name) {
string Input = Name+".in",
Output = Name+".out";
freopen(Input.c_str(), "r", stdin),
freopen(Output.c_str(), "w", stdout);
} const int N = ;
int n, m, Arr[N];
int Ans[N], Tot; inline void Input() {
scanf("%d%d", &n, &m);
For(i, , *m+) {
int x;
scanf("%d", &x);
Arr[x]++;
}
} int Tmp[N];
inline bool Check(int x) {
For(i, , n) {
For(j, , n) Tmp[j] = Arr[j];
Tmp[x]++;
Tmp[i] -= ;
if(Tmp[i] < ) continue; bool flag = ;
Ford(j, n, ) {
if(Tmp[j] < ) {
flag = ;
break;
}
if(!Tmp[j]) continue;
Tmp[j] %= ;
Tmp[j-] -= Tmp[j];
Tmp[j-] -= Tmp[j];
Tmp[j] = ;
}
Tmp[] %= , Tmp[] %= ;
if(Tmp[] || Tmp[]) flag = ; if(flag) return ;
}
return ;
} inline void Solve() {
For(i, , n)
if(Check(i)) Ans[++Tot] = i; if(!Tot) puts("NO");
else {
For(i, , Tot-) printf("%d ", Ans[i]);
printf("%d\n", Ans[Tot]);
}
} int main() {
#ifndef ONLINE_JUDGE
SetIO("");
#endif
Input();
Solve();
return ;
}

这是正着枚举

 #include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <ctime>
using namespace std;
typedef long long LL;
typedef double DB;
#define For(i, s, t) for(int i = (s); i <= (t); i++)
#define Ford(i, s, t) for(int i = (s); i >= (t); i--)
#define Rep(i, t) for(int i = (0); i < (t); i++)
#define Repn(i, t) for(int i = ((t)-1); i >= (0); i--)
#define rep(i, x, t) for(int i = (x); i < (t); i++)
#define MIT (2147483647)
#define INF (1000000001)
#define MLL (1000000000000000001LL)
#define sz(x) ((int) (x).size())
#define clr(x, y) memset(x, y, sizeof(x))
#define puf push_front
#define pub push_back
#define pof pop_front
#define pob pop_back
#define ft first
#define sd second
#define mk make_pair
inline void SetIO(string Name) {
string Input = Name+".in",
Output = Name+".out";
freopen(Input.c_str(), "r", stdin),
freopen(Output.c_str(), "w", stdout);
} const int N = ;
int n, m, Arr[N];
int Ans[N], Tot; inline void Input() {
scanf("%d%d", &n, &m);
For(i, , *m+) {
int x;
scanf("%d", &x);
Arr[x]++;
}
} int Tmp[N];
inline bool Check(int x) {
For(i, , n) {
For(j, , n+) Tmp[j] = Arr[j];
Tmp[x]++;
Tmp[i] -= ;
if(Tmp[i] < ) continue; bool flag = ;
For(j, , n+) {
if(Tmp[j] < ) {
flag = ;
break;
}
if(!Tmp[j]) continue;
Tmp[j] %= ;
Tmp[j+] -= Tmp[j];
Tmp[j+] -= Tmp[j];
Tmp[j] = ;
}
if(flag) return ;
}
return ;
} inline void Solve() {
For(i, , n)
if(Check(i)) Ans[++Tot] = i; if(!Tot) puts("NO");
else {
For(i, , Tot-) printf("%d ", Ans[i]);
printf("%d\n", Ans[Tot]);
}
} int main() {
#ifndef ONLINE_JUDGE
SetIO("");
#endif
Input();
Solve();
return ;
}

//-------------------------------------------------------

大概是想出来如何dp了,不过比较麻烦,但复杂度较低

先是枚举加入的数字,然后dp求解

dp[2][400][1000][1000][1000]

第一位表示是否选择了对子,第二位表示当前进行到了第个数字(设为第x个数字),第三位-第五位表示从第x,x+1,x+2个数字的个数

显然有效状态很少,我们可以用队列和Hash实现这个dp过程

转移时对于每一个状态的转移参考那个优先刻子,其次顺子的贪心策略,推到下一个状态

整个过程的复杂度应该是O(n^2)

听说还有O(n)的dp做法,我再想想

bzoj1028 [JSOI2007]麻将的更多相关文章

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

    http://www.lydsy.com/JudgeOnline/problem.php?id=1028 枚举等待牌 枚举对是哪个 判断 #include<cstdio> #include ...

  2. 【BZOJ1028】[JSOI2007]麻将(贪心)

    [BZOJ1028][JSOI2007]麻将(贪心) 题面 BZOJ 洛谷 题解 感觉好久没打过麻将了,似乎都快不会打了. 这个数据范围看着就觉得是\(O(n^2m)\). 那么就枚举听哪张牌,然后枚 ...

  3. BZOJ 1028: [JSOI2007]麻将 暴力

    1028: [JSOI2007]麻将 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/prob ...

  4. BZOJ 1028 [JSOI2007]麻将

    1028: [JSOI2007]麻将 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1270  Solved: 576[Submit][Status][ ...

  5. 1028: [JSOI2007]麻将

    1028: [JSOI2007]麻将 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2638  Solved: 1168[Submit][Status] ...

  6. [JSOI2007]麻将 模拟 BZOJ1028

    题目描述 麻将是中国传统的娱乐工具之一.麻将牌的牌可以分为字牌(共有东.南.西.北.中.发.白七种)和序数牌(分为条子.饼子.万子三种花色,每种花色各有一到九的九种牌),每种牌各四张. 在麻将中,通常 ...

  7. 【bzoj1028】[JSOI2007]麻将

    首先枚举等待牌,再枚举对子牌.   然后1~n扫一遍,如果现在 s[i]不能被3整除,那么必须跟后两个数搭配几下变成能被3整除的.然后如果能被3整除,那么只要三个连续的一组可行,则三个相同的一组必定也 ...

  8. 1028: [JSOI2007]麻将 - BZOJ

    Description 麻将是中国传统的娱乐工具之一.麻将牌的牌可以分为字牌(共有东.南.西.北.中.发.白七种)和序数牌(分为条子.饼子.万子三种花色,每种花色各有一到九的九种牌),每种牌各四张.在 ...

  9. [JSOI2007]麻将

    Description 麻将是中国传统的娱乐工具之一.麻将牌的牌可以分为字牌(共有东.南.西.北.中.发.白七种)和序数 牌(分为条子.饼子.万子三种花色,每种花色各有一到九的九种牌),每种牌各四张. ...

随机推荐

  1. [POJ1007]DNA Sorting

    [POJ1007]DNA Sorting 试题描述 One measure of ``unsortedness'' in a sequence is the number of pairs of en ...

  2. CreateRemoteThread远程线程注入Dll与Hook

    CreateRemoteThread虽然很容易被检测到,但是在有些场合还是挺有用的.每次想用的时候总想着去找以前的代码,现在在这里记录一下. CreateRemoteThread远程注入 DWORD ...

  3. python4delphi 安装

    环境搭建: 目前p4d已经可以支持到XE7,可惜googlecode即将关闭,不知道作者是否会在github上继续更新. 因为此开源项目历史较久远,拿到源代码后可能还需要手动修改相关的文件引用,毕竟需 ...

  4. OJ 1188 全排列---康托展开

    题目描述 求n的从小到大第m个全排列(n≤20). 输入 n和m 输出 输出第m个全排列,两个数之间有一空格. 样例输入 3 2 样例输出 1 3 2 #include<cstdio> # ...

  5. MFC获取系统当前时间的几种方法

    1.使用CTime类 CString str; //获取系统时间 CTime tm; tm=CTime::GetCurrentTime(); str=tm.Format("现在时间是%Y年% ...

  6. doTjs源码研究笔记

    首先是入口方法 /*tmpl:模板文本 c:用户自定义配置 def:定义编译时执行的数据*/doT.template = function(tmpl, c, def) { } 然后进入第一句代码 c ...

  7. SublimeText3 生成html标签快捷键

    mmet Documentation Syntax Child: > nav>ul>li <nav> <ul> <li></li> & ...

  8. Java单链表、双端链表、有序链表实现

    单链表: insertFirst:在表头插入一个新的链接点,时间复杂度为O(1) deleteFirst:删除表头的链接点,时间复杂度为O(1) 有了这两个方法,就可以用单链表来实现一个栈了,见htt ...

  9. String是引用类型

    关于String为值类型还是引用类型的讨论一直没有平息,最近一直在研究性能方面的问题,今天再次将此问题进行一次明确.希望能给大家带来点帮助. 如果有错误请指出. 来看下面例子: //值类型 ; int ...

  10. tcp粘包问题(封包)

    tcp粘包分析     http://blog.csdn.net/zhangxinrun/article/details/6721495 解决TCP网络传输“粘包”问题(经典)       http: ...