[SNOI2019]纸牌
传送门
Description
有一副纸牌。牌一共有\(n\)种,分别标有 \(1,2,...,n\),每种有\(C\)张。故这副牌共有\(nC\)张。
三张连号的牌(\(i,i+1,i+2\))或三张相同的牌 \((i,i,i)\) 可以组成一叠。如果一组牌可以分成若干(包括零)叠,就称其为一组王牌。
你从牌堆中摸了一些初始牌。现在你想再挑出一些牌组成一组王牌,请问有多少种可能组成的王牌呢?答案对\(998244353\)取模。
两组牌相同当且仅当它们含有的每一种牌数量都相同。
Solution
发现这道题中的\(n\)很大,所以考虑矩阵乘法
发现\((i,i+1,i+2)\)这样的牌,对于相同的\(i\),最多只有两叠
所以考虑一个\(3*3\)的状态表示当前数\(i\)与\(i-1\)开始的顺子的数量\((0,1,2)\)
考虑如何转化到下一个数,发现需要枚举\(i+1\)开始的顺子数,将其乘上可行的\((i+1,i+1,i+1)\)的数量的个数
将原题的\(dp\)转化位矩阵乘法
对于已经有初始牌的数,我们考虑单独拿出来转移
可以先把转移矩阵的次幂算出来,减小常数
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define reg register
#define int ll
inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
const int P=998244353,MX=1005;
ll n,C,X,A[MX],K[MX];
int Mul(int x,int y){return (1LL*x*y)%P;}
int Add(int x,int y){return (x+y)%P;}
struct Matrix
{
	int a[9][9];
	Matrix(){memset(a,0,sizeof a);}
	void emp(){for(int i=0;i<9;++i)a[i][i]=1;}
	Matrix operator *(Matrix b)
	{
		Matrix c;
		register int i,j,k;
		for(k=0;k<9;++k)for(i=0;i<9;++i)for(j=0;j<9;++j)
		c.a[i][j]=Add(c.a[i][j],Mul(b.a[i][k],a[k][j]));
		return c;
	}
}tmp,opt[70],ans;
Matrix OPT(int m)
{
	Matrix r;int x=0;r.emp();
	for(;m;m>>=1,++x)if(m&1)r=r*opt[x];
	return r;
}
signed main()
{
	n=read();C=read();X=read();
	register int i,j,k,l;
	for(i=1;i<=X;++i) K[i]=read(),A[i]=read();
	for(i=0;i<3;++i)for(j=0;j<3;++j)for(k=0;k<3;++k)
		if(i+j+k<=C)opt[0].a[j*3+k][i*3+j]=1+(C-i-j-k)/3;
	for(i=1;i<70;++i) opt[i]=opt[i-1]*opt[i-1];
	ans.a[0][0]=1;
	for(l=1;l<=X;++l)
	{
		ans=ans*OPT(K[l]-K[l-1]-1);
		memset(tmp.a,0,sizeof tmp.a);
		for(i=0;i<3;++i)for(j=0;j<3;++j)for(k=0;k<3;++k)
		{
			int least=i+j+k;
	        if(least<A[l]) least=A[l]+((least-A[l])%3+3)%3;
            if(least<=C) tmp.a[j*3+k][i*3+j]=1+(C-least)/3;
		}
		ans=ans*tmp;
	}
	ans=ans*OPT(n-K[X]);
	printf("%lld\n",ans.a[0][0]);
	return 0;
}
Blog来自PaperCloud,未经允许,请勿转载,TKS!
[SNOI2019]纸牌的更多相关文章
- luogu P5371 [SNOI2019]纸牌
		传送门 打麻将+1(雾 有顺子这种东西...注意到以某个位置为开头的顺子数量最多为2,那么有个想法就是枚举以每个位置为开头的顺子个数,然后每个位置的刻子的取法个数为\(\lceil\frac{\tex ... 
- 【LOJ】#3098. 「SNOI2019」纸牌
		LOJ#3098. 「SNOI2019」纸牌 显然选三个以上的连续牌可以把他们拆分成三个三张相等的 于是可以压\((j,k)\)为有\(j\)个连续两个的,有\(k\)个连续一个的 如果当前有\(i\ ... 
- code vs 1098 均分纸牌(贪心)
		1098 均分纸牌 2002年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 有 N 堆纸牌 ... 
- C语言-纸牌计算24点小游戏
		C语言实现纸牌计算24点小游戏 利用系统时间设定随机种子生成4个随机数,并对4个数字之间的运算次序以及运算符号进行枚举,从而计算判断是否能得出24,以达到程序目的.程序主要功能已完成,目前还有部分细节 ... 
- 一起来做webgame,《Javascript蜘蛛纸牌》
		不得不说,做游戏是会上瘾的,这次带来的是win系统上的经典游戏<蜘蛛纸牌>,不能完美,但求一玩 移牌 0 次 Javascript game_蜘蛛纸牌 正在努力加载... // " ... 
- 洛谷 P1031 均分纸牌 Label:续命模拟QAQ
		题目描述 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 ... 
- 斯坦福iOS7公开课1-3笔记及纸牌Demo
		1.MVC Model:模型 描述程序是什么,例如数据库操作之类的行文以及纸牌Demo里纸牌玩法都是写在Model这一层,通过Notification和KVO(后续文章会介绍)两种方式与Control ... 
- [CareerCup] 8.1 Implement Blackjack 实现21点纸牌
		8.1 Design the data structures for a generic deck of cards. Explain how you would subclass the data ... 
- 纸牌project
		用range[0,8)的列表表示牌,这些数字要出现两次.我们建议你通过连接两个range[0,8)的列表来创建这个list.利用Docs来安排列表串联操作 写一个draw handler啥样的draw ... 
随机推荐
- [golang]使用gomail发邮件(在Go中发送电子邮件的最佳方式)
			1 前言 定义邮箱服务器连接信息,如果是网易邮箱 pass填密码,qq邮箱填授权码(客户端专用密码). gomail包: go get gopkg.in/gomail.v2 更多功能可以参考 http ... 
- C++字符串相互转换
			转自cs_wu原文 C++ char*,const char*,string的相互转换 1. string转const char* string s ="abc"; const c ... 
- vue项目中添加单元测试
			从网上找了很多例子关于单元测试,都是如何新建项目的时候的添加单元测试,用vue-cli中怎么添加,但是我的项目已经生成了,不能再一次重新初始化,这时如何添加单元测试,这里面遇到了好多坑,写在这里记录一 ... 
- Django:RestFramework之-------渲染器
			12.渲染器 from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer,AdminRenderer class Te ... 
- JAVA基础之HttpServletRequest请求
			HttpServletRequest请求是获取请求行.请求头和请求体:可以通过这个方法设置防盗链,获取地址.牢记解决乱码的方式. 怎么选择是重定向还是转发呢?通常情况下转发更快,而且能保持reques ... 
- js删除对象里的某一个属性
			var a={"id":1,"name":"danlis"}; //添加属性 a.age=18; console.log(a); //结果: ... 
- caement Archaic spelling of cement
			caement Archaic spelling of cement. caement Alternative forms[edit] caement (archaic) cæment (archai ... 
- Pytorch 张量维度
			Tensor类的成员函数dim()可以返回张量的维度,shape属性与成员函数size()返回张量的具体维度分量,如下代码定义了一个两行三列的张量: f = torch.randn(2, 3) pri ... 
- 深入理解JVM-java虚拟机栈
			1.java虚拟机栈 1. Java虚拟机栈也是线程私有的,它的生命周期与线程相同(随线程而生,随线程而灭) 2. 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowErro ... 
- Python学习日记(二十九) 网络编程
			早期的计算机通信需要有一个中间件,A要给B传东西,A必须要把信息传给中间件,B再把从中间件中拿到信息 由于不同机器之间需要通信就产生了网络 软件开发的架构 1.C/S架构 服务器-客户机,即Clien ... 
