传送门

打麻将+1(雾

有顺子这种东西...注意到以某个位置为开头的顺子数量最多为2,那么有个想法就是枚举以每个位置为开头的顺子个数,然后每个位置的刻子的取法个数为\(\lceil\frac{\text{剩下的牌数}}{3}\rceil\),乘起来,然后每种情况的和就是答案

所以设\(f_{i,j,k}\)表示放到\(i\)牌,有\(j\)个\(i-1,i,i+1\)以及\(k\)个\(i,i+1,i+2\)的方案.转移枚举下一位放多少顺子(注意最后两个位置只能放0个),然后乘上刻子的取法个数进行转移,因为有些位置必须要用一些牌,所以方案应该改为(下面\(x\)为这一位用顺子消耗的牌数,\(a\)为这一位至少要用的牌数)$$\begin{cases}\lceil\frac{c-x}{3}\rceil&,x\ge a\\lceil\frac{c-(x+3 \lceil\frac{a-x}{3}\rceil)}{3}\rceil&,x< a\end{cases}$$

然后注意到\(n\)很大,并且很多位置都是随便用任意张牌,然后有限制的地方很少,所以有限制的地方以及最后两位暴力转移,剩下的地方矩乘转移

// luogu-judger-enable-o2
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define db double using namespace std;
const int N=1000+10,mod=998244353;
LL rd()
{
LL x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
struct matrix
{
int a[9][9];
matrix(){memset(a,0,sizeof(a));}
matrix operator * (const matrix &bb) const
{
matrix an;
for(int i=0;i<9;++i)
for(int j=0;j<9;++j)
{
LL nw=0;
for(int k=0;k<9;++k) nw+=1ll*a[i][k]*bb.a[k][j];
an.a[i][j]=nw%mod;
}
return an;
}
matrix operator ^ (const LL &bb) const
{
matrix an,a=*this;
for(int i=0;i<9;++i) an.a[i][i]=1;
LL b=bb;
while(b)
{
if(b&1) an=an*a;
a=a*a,b>>=1;
}
return an;
}
}aa,bb;
LL n,a[N][2];
int c,m,id[3][3],tmp[9]; int main()
{
n=rd(),c=rd(),m=rd();
for(int i=1;i<=m;++i) a[i][0]=rd(),a[i][1]=rd();
a[m+1][0]=n+1;
int ii=0;
aa.a[0][0]=1;
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
id[i][j]=i*3+j;
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
for(int k=0;k<3;++k)
bb.a[id[i][j]][id[j][k]]=max((c-i-j-k+3)/3,0);
for(;ii<=m;)
{
LL l=max(min(n-2,a[ii+1][0]-1)-(a[ii][0]+1)+1,0ll);
aa=aa*(bb^l);
++ii;
if(a[ii][0]>n-2) break;
memset(tmp,0,sizeof(tmp));
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
for(int k=0;k<3;++k)
{
int num=i+j+k<=a[ii][1]?i+j+k+(a[ii][1]-i-j-k+2)/3*3:i+j+k;
tmp[id[j][k]]=(tmp[id[j][k]]+1ll*aa.a[0][id[i][j]]*max((c-num+3)/3,0)%mod)%mod;
}
memcpy(aa.a[0],tmp,sizeof(tmp));
}
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
for(int k=1;k<3;++k)
bb.a[id[i][j]][id[j][k]]=0;
for(LL h=n-1;h<=n;++h,++ii)
{
while(h<=n&&h<a[ii][0]) aa=aa*bb,++h;
if(h>n) break;
memset(tmp,0,sizeof(tmp));
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
{
int num=i+j<=a[ii][1]?i+j+(a[ii][1]-i-j+2)/3*3:i+j;
tmp[id[j][0]]=(tmp[id[j][0]]+1ll*aa.a[0][id[i][j]]*max((c-num+3)/3,0)%mod)%mod;
}
memcpy(aa.a[0],tmp,sizeof(tmp));
}
printf("%d\n",aa.a[0][0]);
return 0;
}

最新文章

  1. ueditor工具栏新增按钮教程
  2. C# 的界面控件属性修改线程安全问题
  3. BZOJ 2705: [SDOI2012]Longge的问题
  4. MySQL 主从热备份(读写分离)
  5. windows环境下局域网内无法访问apache站点
  6. css position 绝对定位和相对定位
  7. (转)mongoDB 禁用大内存页面 transparent_hugepage=never
  8. DB天气app冲刺第十二天
  9. LCMS
  10. 写自己的WPF样式 - 窗体
  11. jquery uploadify插件多文件上传
  12. [Oracle]日期和毫秒转换(Date-&gt;int)
  13. 使用EXTEND方式来分段处理大表的搬数据
  14. 集群/分布式环境下5种session处理策略
  15. 安装cocoa pods时出现Operation not permitted - /usr/bin/xcodeproj的问题
  16. Android网页打开指定App
  17. 三星Galaxy S10可望率先应用于1TB的手机内存
  18. 最棒的 JavaScript 学习指南(2018版)
  19. storm+Calcite
  20. 转载:Linux操作系统(1.3.1)《深入理解Nginx》(陶辉)

热门文章

  1. linux文档与目录的相关命令
  2. Override和Overload的含义与区别
  3. http服务配置和apache
  4. 字符 kotlin(3)
  5. P1200 [USACO1.1]你的飞碟在这儿Your Ride Is He…
  6. Rate 评分
  7. Linux_系统破坏性修复实验
  8. LeetCode.997-找到镇法官(Find the Town Judge)
  9. javase程序设计上机作业1
  10. 双系统正确卸载Ubuntu系统