ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

麻将

2022-05-21 14:36:05  阅读:140  来源: 互联网

标签:刻子 puts int solve 麻将 编号 顺子


来源:第四届图灵杯趣味网络邀请赛
https://xjoi.net/contest/4228
https://contest.xinyoudui.com/statements/22a/b21510ada25e/statement_zh.html

有n种牌,编号从1到n,第i种牌有a[i]张。

给定常数x和y,问能否把这些牌分成若干组,每组满足下列条件之一:

刻子:包含x张编号相同的牌。 顺子:包含y张编号不同但连续的牌。

\(1<=n<=10^3,1<=x,y<=10^9\)

引理:如果能够成功分组,一定存在一种合法的分组方案使得编号最小的牌尽可能地组成刻子。

比如\({n=2x+1}\),考虑两种分法,分成2个刻子1个顺子 或 1个刻子x+1个顺子。

考虑每个顺子都是从编号1到y,x+1个顺子其实也就相当于编号1到y每个都组成一个刻子,然后总体是一个顺子。

所以所有方案其实都可以转化成刻子最多的那种方案。从前往后,重复子问题。

//模拟 O(N^2)
bool solve(){
	for(int i=1;i<=n-y+1;i++){
		a[i] %= x;
		for(int j=i+1;j<i+y;j++){
			if(a[j] < a[i]) return false;
			a[j] -= a[i];
		}
	}
	for(int i=n-y+2;i<=n;i++)
		if(a[i] % x) return false;
	return true;
}
int main(){
	cin>>n>>x>>y;
	for(int i=1;i<=n;i++) cin>>a[i];
	if(solve()) puts("Yes");
	else puts("No");
	return 0;
}

//差分优化 O(N) 一次可以直接修改整个范围
bool solve(){
	int tmp = 0;
	for(int i=1;i<=n-y+1;i++){
		tmp += b[i];//此时tmp即为a[i] 
		if(tmp < 0) return false;
		int r = tmp % x;//全做成刻子后剩下的 
		//相当于a[i]~a[i+y-1]每个数都减去了r 
		tmp -= r;
		b[i+y] += r;
	}
	for(int i=n-y+2;i<=n;i++){
		tmp += b[i];
		if(tmp < 0) return false;
		if(tmp % x) return false;
	}
	return true;
}
int main(){
	cin>>n>>x>>y;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		b[i] = a[i] - a[i-1];
	}
	if(solve()) puts("Yes");
	else puts("No");
	return 0;
} 

标签:刻子,puts,int,solve,麻将,编号,顺子
来源: https://www.cnblogs.com/dtdbm/p/16294999.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有