[bzoj 1028] [JSOI2007]麻将

忽略花色, 每种牌数量无限. 顺子是序数相连的三张牌, 刻子是序数相同的三张牌, 对子是序数相同的两张牌. 一组和了的牌由(3m+2)张牌组成: 一个对子, 其余每3张一组, 每组是顺子或刻子. 听牌是还差一张就可以和的牌. 判断某组牌是否是听牌, 如果是, 从小到大输出所有可能的等待牌. (9≤n≤400, 4≤m≤1000) n≤400, 不妨枚举等待牌, 判断是否和了. 判断牌是否和了, 可以枚举一下对子, 判断剩下的牌是否能分成合法的m组. 数据规模不允许DP. 贪心的话, 不管是先找出所有的顺子, 还是先找出所有的刻子, 都举出了反例......

题解说, 扫一遍, 对于每种牌, 先考虑刻子, 再考虑和后面的牌组成顺子.

不妨设序数最小的牌是1, 共x张. 如果能和, 考虑一种方案: a张组成刻子, b张和后面的2,3组成顺子. 这说明, 2,3也至少各有b张. 不妨把(b-b mod 3)张1,2,3换成刻子. 对所有的顺子均进行这样的操作. 可以看到 (脑补一下), 改造后的方案就是我们的贪心算法所得到的.

这类的贪心我也不知道该怎么对付...... TAT

斯里尼瓦瑟·拉马努金(泰米尔语:ஸ்ரீனிவாஸ ராமானுஜன் ஐயங்கார்,转写:Srīṉivāsa Rāmāṉujan Aiyaṅkār,又译拉马努詹,1887年12月22日-1920年4月26日)是印度历史上最著名的数学家之一。
他没受过正规的高等数学教育,沉迷数论,尤爱牵涉π、质数等数学常数的求和公式,以及整数分拆。惯以直觉(或者是跳步)导出公式,不喜作证明(事后往往证明他是对的)。他留下的那些没有证明的公式,引发了后来的大量研究。

培养直觉?

#define x first
#define y second

const int N = 400;

int a[N+3], b[N+3];

int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	rep (_, 0, 3*m+1) {
		int i;
		scanf("%d", &i);
		++a[i];
	}

	int cnt = 0;
	
	rep (i, 1, n+1) {
		bool ok = false;
		++a[i];
		rep (j, 1, n+1) if (a[j] >= 2) {
			bool flag = true;
			copy(a+1, a+n+1, b+1);
			b[j] -= 2;
			rep (k, 1, n+1) {
				b[k] %= 3;
				if (b[k]) {
					int t = min(b[k], min(b[k+1], b[k+2]));
					b[k] -= t, b[k+1] -= t, b[k+2] -= t;
					if (b[k]) {
						flag = false;
						break;
					}
				}
			}
			if (flag) {
				ok = true;
				break;
			}
		}
		--a[i];
		if (ok) {
			if (cnt++) putchar(' ');
			printf("%d", i);
		}
	}

	if (!cnt) printf("NO");
	
	puts("");
	return 0;
}