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. OpenGL顶点缓冲区对象(VBO)

    转载 http://blog.csdn.net/dreamcs/article/details/7702701 创建VBO        GL_ARB_vertex_buffer_object 扩展可 ...

  2. 重新编译安装gcc-4.1.2(gcc版本降级)之TFS安装

    wget http://gcc.parentingamerica.com/releases/gcc-4.1.2/gcc-4.1.2.tar.gz tar -zxfv gcc-4.1.2.tar.gz ...

  3. Maximum Product Subarray

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  4. python操作Excel读写--使用xlrd

    一.安装xlrd模块 到python官网下载http://pypi.python.org/pypi/xlrd模块安装,前提是已经安装了python 环境. 二.使用介绍 1.导入模块 import x ...

  5. iOS UITableView 的beginUpdates和endUpdates

    在官方文档中是这样介绍beginUpdates的 Call this method if you want subsequent insertions, deletion, and selection ...

  6. Java for LeetCode 191 Number of 1 Bits

    Write a function that takes an unsigned integer and returns the number of ’1' bits it has (also know ...

  7. Java for LeetCode 187 Repeated DNA Sequences

    All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACG ...

  8. 中石油—2的幂次方(power)

    问题 E: 2的幂次方(power) 时间限制: 1 Sec  内存限制: 64 MB提交: 38  解决: 19[提交][状态][讨论版] 题目描述 任何一个正整数都可以用2的幂次方表示.例如:13 ...

  9. BestCoder9 1003 Revenge of kNN(hdu 4995) 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4995 题目意思:在一个一维坐标轴上,给出位置 xi 和值 vi,对于 M 次询问,每次询问给出inde ...

  10. springMVC获取file,几种转换

    //从前台通过name值获取file MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)reque ...