题目大意

用 \(p\) 种颜色填 \(n\times m\) 的画板,要求任意相邻两列的颜色数都不少于 \(q\) ,求方案数。

数据范围

\(1\leq n\leq 100,1\leq m\leq 10^9,q\leq p\leq 100\)

思路

观摩 \(m\) 的范围,显然需要一个 \(\log m\) 的做法,于是想到了矩阵快速幂。

首先考虑原始的转移。若当前一列涂上 \(j\) 种颜色,下一列要涂 \(k\) 种颜色,则方案数如下:

\[\sum \limits_{x=\max(q,j,k)}^{\min(p,j+k)}C_j^{j+k-x}C_{p-i}^{x-j}
\]

前一个组合数是 \(j\) 和 \(k\) 颜色中交集的部分,而后一个就是交集的补集。其中边界的意思分别为 \(j\cap k=\varnothing\) 和 \(j\subset k\) 或 \(k\subset j\)。意思就是说,这次的方案组成就是在满足条件的情况下,和上次相交的颜色的选择的方案乘上这次的新颜色的选择的方案。

然后对于每一列,定义 \(g[i][j]\),表示当前填到第 \(i\) 行的格子,涂 \(j\) 种颜色的方案数。则 \(g[n][j]\) 一列中涂 \(n\) 种颜色的方案。这个问题可以转化成有 \(j\) 个不同的盒子,要把 \(i\) 个不同的球放入盒子中,要求非空。这个问题就是第二类斯特林,递推式为:

\[g[i][j]=(g[i-1][j-1]+g[i-1][j])\times j
\]

即可以在放过球的盒子中再放一个,有 \(j\) 种,也可以新选一个没有放过球的盒子,这个新的盒子可以是 \(j\) 中的任何一个。因此一共 \(j\) 种。由于每一列的情况都是类似的,所以可以预处理出来。

那么转移矩阵就出来了。设 \(h[j][k]\) 表示这一列涂 \(j\) 种颜色,下一列涂 \(k\) 种颜色的方案数:

\[h[j][k]=g[n][j]\cdot\sum \limits_{x=\max(q,j,k)}^{\min(p,j+k)}C_j^{j+k-x}C_{p-i}^{x-j}
\]

则令 \(f[i][j]\) 为当前选到第 \(i\) 列,当前一列涂了 \(j\) 种颜色的方案数,则可以得到 \(f[i][j]=f[i-1][j]\times h[j][k]\),边界为 \(f[1][j]=g[n][j]\times C_p^j\),表示选 \(j\) 种颜色后涂上。由于 \(f\) 的转移系数与 \(i\) 无关,所以可以用矩阵快速幂优化转移 \(m-1\) 次后得到结果,时间复杂度 \(O(n^3\log m)\)。

代码

注意卡常。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100+10;
const int Mod=998244353;
int n,m,p,q;
ll res;
ll C[maxn][maxn],g[maxn][maxn]; inline ll add(ll x,ll y){
if(x+y>Mod)return x+y-Mod;
return x+y;
} struct Mat{
ll a[maxn][maxn];
Mat(){
memset(a,0,sizeof(a));
}
inline void set(){
for(int i=1;i<=n;i++)
a[i][i]=1;
}
friend inline Mat operator *(register const Mat& A,register const Mat& B){
Mat C;
for(register int i=1;i<=p;i++)
for(register int j=1;j<=p;j++)
for(register int k=1;k<=p;k++)
C.a[i][j]=add(C.a[i][j],A.a[i][k]*B.a[k][j]%Mod);
return C;
}
}f,h; inline int read(){
int x=0;bool fopt=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
return fopt?x:-x;
} inline Mat qpow(Mat x,int b){
Mat ans,base=x;
ans.set();
while(b){
if(b&1)ans=ans*base;
base=base*base;
b>>=1;
}
return ans;
} inline void Init(){
g[0][0]=C[0][0]=1;
for(int i=1;i<=100;i++){
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=add(C[i-1][j],C[i-1][j-1]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
g[i][j]=add(g[i-1][j],g[i-1][j-1])*j%Mod;
} signed main(){
n=read();m=read();p=read();q=read();
Init();
for(register int j=1;j<=p;j++)
for(register int k=1;k<=p;k++){
int l=max(max(q,j),k),r=min(p,j+k);
for(register int i=l;i<=r;i++)
h.a[j][k]=add(h.a[j][k],C[j][j+k-i]*C[p-j][i-j]%Mod);
h.a[j][k]=h.a[j][k]*g[n][k]%Mod;
}
f=qpow(h,m-1);
for(register int i=1;i<=p;i++)
for(register int j=1;j<=p;j++)
res=add(res,f.a[i][j]*C[p][i]%Mod*g[n][i]%Mod);//简单易懂的求和
printf("%lld\n",res);
return 0;
}

【矩阵乘优化DP】涂色游戏的更多相关文章

  1. CodeForces621E 快速矩阵幂优化dp

    有时些候在用快速矩阵幂优化dp的时候,它的矩阵乘法是不那么容易被具体为题目背景的意思的,大多数时候难以理解矩阵之间相乘的实际意义,正如有时候我们不知道现在在做手头这些事情的意义,但倘若是因一个目标而去 ...

  2. 形态形成场(矩阵乘法优化dp)

    形态形成场(矩阵乘法优化dp) 短信中将会涉及前\(k\)种大写字母,每个大写字母都有一个对应的替换式\(Si\),替换式中只会出现大写字母和数字,比如\(A→BB,B→CC0,C→123\),代表 ...

  3. 斐波那契数列 矩阵乘法优化DP

    斐波那契数列 矩阵乘法优化DP 求\(f(n) \%1000000007​\),\(n\le 10^{18}​\) 矩阵乘法:\(i\times k\)的矩阵\(A\)乘\(k\times j\)的矩 ...

  4. [CSP-S模拟测试]:涂色游戏(DP+组合数+矩阵快速幂)

    题目描述 小$A$和小$B$在做游戏.他们找到了一个$n$行$m$列呈网格状的画板.小$A$拿出了$p$支不同颜色的画笔,开始在上面涂色.看到小$A$涂好的画板,小$B$觉得颜色太单调了,于是把画板擦 ...

  5. NOIp十连测 涂色游戏

    [问题描述]小A 和小B 在做游戏.他们找到了一个n 行m 列呈网格状的画板.小A 拿出了p 支不同颜色的画笔,开始在上面涂色.看到小A 涂好的画板,小B 觉得颜色太单调了,于是把画板擦干净,希望涂上 ...

  6. hdu 4559 涂色游戏(对SG函数的深入理解,推导打SG表)

    提议分析: 1 <= N <= 4747 很明显应该不会有规律的,打表发现真没有 按题意应该分成两种情况考虑,然后求其异或(SG函数性质) (1)找出单独的一个(一列中只有一个) (2)找 ...

  7. [BZOJ 1009] [HNOI2008] GT考试 【AC自动机 + 矩阵乘法优化DP】

    题目链接:BZOJ - 1009 题目分析 题目要求求出不包含给定字符串的长度为 n 的字符串的数量. 既然这样,应该就是 KMP + DP ,用 f[i][j] 表示长度为 i ,匹配到模式串第 j ...

  8. 矩阵乘法优化DP

    本文讲一下一些基本的矩阵优化DP的方法技巧. 定义三个矩阵A,B,C,其中行和列分别为$m\times n,n \times p,m\times p$,(其中行是从上往下数的,列是从左往右数的) $C ...

  9. hdu 4559 涂色游戏(SG)

    在一个2*N的格子上,Alice和Bob又开始了新游戏之旅. 这些格子中的一些已经被涂过色,Alice和Bob轮流在这些格子里进行涂色操作,使用两种涂色工具,第一种可以涂色任意一个格子,第二种可以涂色 ...

  10. 【循环矩阵乘优化DP】BZOJ 2510 弱题

    题目大意 有 \(M\) 个球,一开始每个球均有一个初始标号,标号范围为 \(1\) - \(N\) 且为整数,标号为 \(i\) 的球有 \(a_i\) 个,并保证 \(\sum a_i = M\) ...

随机推荐

  1. python django 简单接口测试页面

    项目创建订单只能是接口创建的,之前都是用jar包放到jmeter里调用下单,给产品或者运维用不太方便,就想用django写一个带前端界面的下单web程序 项目结构 代码,比较渣 # coding=ut ...

  2. Java I/O流 复制文件速度对比

    Java I/O流 复制文件速度对比 首先来说明如何使用Java的IO流实现文件的复制: 第一步肯定是要获取文件 这里使用字节流,一会我们会对视频进行复制(视频为非文本文件,故使用之) FileInp ...

  3. mysql修改默认数据存储路径

    1.先关闭mysql服务 可cmd--services.msc进入关闭服务 或cmd命令输入net stop mysql57关闭服务 2.进入C:\ProgramData\MySQL\MySQL Se ...

  4. oracle之三rman 备份

    rman 备份 7.1 归档方式下rman备份常用语法: 7.1.1 backup 备份 1)备份全库:1.1 RMAN> backup database format='/u01/myrman ...

  5. 被喷了!聊聊我开源的RPC框架那些事

    前段时间利用业余时间写了一个简单的 RPC 框架,花费了不少精力.开源出来之后,少部分不太友好的技术人站在上帝视角说了风凉话.就很难受,兄弟,谁还没有一个玻璃心. 简单吐槽一波,给大家聊聊关于 gui ...

  6. netty之handler read

    有时候会有一系列的处理in的handler,使用fireChannelRead处理传递 转载自https://blog.csdn.net/u011702633/article/details/8205 ...

  7. 写一个简单的 Linux Shell (C++)

    这里可以找到代码 github.com/z0gSh1u/expshell 支持的特性 单条指令的执行 引号引起的参数(如 $ some_program "hello, world" ...

  8. 本周 GitHub 速览:您的代码有声儿吗?(Vol.38)

    作者:HelloGitHub-小鱼干 摘要:还记得花式夸赞程序员的彩虹屁插件 vscode-rainbow-fart 吗?它后续有人啦!JazzIt 同它的前辈 vscode-rainbow-fart ...

  9. 龙芯3A4000-Debian 10上常用软件记录

    所用平台 硬件:龙芯3a4000 (MIPS64el) 操作系统:Debian 10(buster)+ MATE桌面 内核版本:4.19.90 以下所有软件同样适用于x86体系结构的Linux发行版. ...

  10. if else与switch for与foreach

    if...else...适用于变量判断 switch适用于常量判断(switch只判断一次,if else 判断多次) foreach只适用于集合和数组查询(foreach不支持增加删除操作) for ...