联赛模拟测试5 涂色游戏 矩阵优化DP
题目描述

分析
定义出\(dp[i][j]\)为第\(i\)列涂\(j\)种颜色的方案数
然后我们要解决几个问题
首先是求出某一列涂恰好\(i\)种颜色的方案数\(d[i]\)
如果没有限制必须涂\(i\)种,而是有的颜色可以不涂,那么方案数为\(i^n\)
为了避免少涂的情况,我们减去只涂\(1 \sim i-1\)种颜色的方案数
即\(d[i]=i^n-\sum_{j=1}^{i-1}C_i^j \times d[j]\)
初始化为\(d[1]=1\)
接下来考虑转移
\(f[i][j]=f[i-1][k] \times d[j] \times C_k^{cf} \times C_{p-k}^{j-cf}\)
其中\(i\)为当前列的编号,\(j\)为当前列选了几种颜色,\(k\)为上一列选了几种颜色,\(cf\)为这些颜色有几种相同的
注意两个组合数不能写成\(C_j^{cf} \times C_{p-j}^{k-cf}\)
因为我们要选出\(j\)个,而不是\(k\)个
时间复杂度\(m \times n^3\)
期望得分:\(40\),实际得分:\(50\)
下一步我们考虑怎么优化
我们会发现,如果\(j\)和\(k\)确定了,那么\(f[i-1][k]\)乘的系数就确定了
根据乘法分配率,我们可以把系数预处理出来,优化掉一维
时间复杂度\(m \times n^2\)
期望得分:\(70\),实际得分:\(70\)
我们继续观察会发现,每一列的转移乘的系数都是固定的
结合\(m\)的大小,我们可以使用矩阵快速幂优化
时间复杂度\(logm \times n^3\)
期望得分:\(100\),实际得分:\(70\)
因为出题人卡常卡到丧心病狂,最后几个点仍然会跑到\(2s\)多
所以我们要优化代码的常数
能不用\(longlong\)就不用\(longlong\)
减少取模的次数
加几个玄学的\(register\)和\(inline\)
再手动吸一下氧就可以了
时间复杂度\(logm \times n^3\)
期望得分:\(100\),实际得分:\(100\)
代码
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define fastcall __attribute__((optimize("-O3")))
%:pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
%:pragma GCC optimize("-fgcse")
%:pragma GCC optimize("-fgcse-lm")
%:pragma GCC optimize("-fipa-sra")
%:pragma GCC optimize("-ftree-pre")
%:pragma GCC optimize("-ftree-vrp")
%:pragma GCC optimize("-fpeephole2")
%:pragma GCC optimize("-ffast-math")
%:pragma GCC optimize("-fsched-spec")
%:pragma GCC optimize("unroll-loops")
%:pragma GCC optimize("-falign-jumps")
%:pragma GCC optimize("-falign-loops")
%:pragma GCC optimize("-falign-labels")
%:pragma GCC optimize("-fdevirtualize")
%:pragma GCC optimize("-fcaller-saves")
%:pragma GCC optimize("-fcrossjumping")
%:pragma GCC optimize("-fthread-jumps")
%:pragma GCC optimize("-funroll-loops")
%:pragma GCC optimize("-freorder-blocks")
%:pragma GCC optimize("-fschedule-insns")
%:pragma GCC optimize("inline-functions")
%:pragma GCC optimize("-ftree-tail-merge")
%:pragma GCC optimize("-fschedule-insns2")
%:pragma GCC optimize("-fstrict-aliasing")
%:pragma GCC optimize("-falign-functions")
%:pragma GCC optimize("-fcse-follow-jumps")
%:pragma GCC optimize("-fsched-interblock")
%:pragma GCC optimize("-fpartial-inlining")
%:pragma GCC optimize("no-stack-protector")
%:pragma GCC optimize("-freorder-functions")
%:pragma GCC optimize("-findirect-inlining")
%:pragma GCC optimize("-fhoist-adjacent-loads")
%:pragma GCC optimize("-frerun-cse-after-loop")
%:pragma GCC optimize("inline-small-functions")
%:pragma GCC optimize("-finline-small-functions")
%:pragma GCC optimize("-ftree-switch-conversion")
%:pragma GCC optimize("-foptimize-sibling-calls")
%:pragma GCC optimize("-fexpensive-optimizations")
%:pragma GCC optimize("inline-functions-called-once")
%:pragma GCC optimize("-fdelete-null-pointer-checks")
const int maxn=1e4+5;
const int maxm=105;
const int maxp=1e4+5;
const int mod=998244353;
int ny[maxn],jc[maxn],jcc[maxn],f[maxp][maxm],n,m,p,q,d[maxm],xs[maxm][maxm];
int a[maxm][maxm];
int ans;
int getC(int nn,int mm){
return 1LL*jc[nn]*jcc[mm]%mod*jcc[nn-mm]%mod;
}
int ksm(int ds,int zs){
int ans=1;
while(zs){
if(zs&1) ans=1LL*ans*ds%mod;
ds=1LL*ds*ds%mod;
zs>>=1;
}
return ans;
}
struct asd{
int sz[maxm][maxm];
asd(){
memset(sz,0,sizeof(sz));
}
}da,xss;
#define reg register
asd cf(asd aa,asd bb){
asd cc;
for(reg int i=1;i<maxm;i++){
for(reg int j=1;j<maxm;j++){
for(reg int k=1;k<maxm;k++){
cc.sz[i][j]=(cc.sz[i][j]+1LL*aa.sz[i][k]*bb.sz[k][j]%mod);
if(cc.sz[i][j]>=mod) cc.sz[i][j]-=mod;
}
}
}
return cc;
}
int main(){
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&p,&q);
ny[1]=1;
for(int i=2;i<maxm;i++){
ny[i]=1LL*(mod-mod/i)*ny[mod%i]%mod;
}
jc[0]=jcc[0]=1;
for(int i=1;i<maxm;i++){
jc[i]=1LL*jc[i-1]*i%mod;
jcc[i]=1LL*jcc[i-1]*ny[i]%mod;
}
int mmax=std::min(n,p);
d[1]=1;
for(reg int i=2;i<=mmax;i++){
d[i]=ksm(i,n);
for(reg int j=1;j<i;j++){
d[i]=(d[i]-1LL*d[j]*getC(i,j)%mod+mod);
if(d[i]>=mod) d[i]-=mod;
}
}
for(reg int i=1;i<=mmax;i++){
f[1][i]=1LL*getC(p,i)*d[i]%mod;
da.sz[i][1]=f[1][i];
}
for(reg int j=1;j<=mmax;j++){
for(reg int k=1;k<=mmax;k++){
int noww=std::min(j,k);
for(reg int cf=0;cf<=noww;cf++){
if(j+k-cf<q || j+k-cf>p) continue;
xs[j][k]=(xs[j][k]+1LL*d[j]*getC(k,cf)%mod*getC(p-k,j-cf)%mod);
if(xs[j][k]>=mod) xs[j][k]-=mod;
xss.sz[j][k]=xs[j][k];
}
}
}
m--;
while(m){
if(m&1) da=cf(xss,da);
m>>=1;
xss=cf(xss,xss);
}
for(int i=1;i<=mmax;i++){
ans+=da.sz[i][1];
if(ans>=mod) ans-=mod;
}
printf("%d\n",ans);
return 0;
}
联赛模拟测试5 涂色游戏 矩阵优化DP的更多相关文章
- LYDSY模拟赛day3 涂色游戏
/* 非常好的题 */ #include <cstdio> #include <iostream> #include <cstdlib> #include < ...
- 「模拟8.21」山洞(矩阵优化DP)
暴力: 正解: 考虑循环矩阵,f[i][j]表示从i点到j点的方案数 我们发现n很小,我们预处理出n次的f[i][j] 然后在矩阵快速幂中,我们要从当前的f[i][j]*f[j][k]-->fi ...
- [CSP-S模拟测试]:数对(线段树优化DP)
题目传送门(内部题96) 输入格式 第一行一个整数$n$,接下来$n$行每行三个整数$a_i,b_i,w_i$. 输出格式 一行一个整数表示最大权值和. 样例 样例输入: 54 4 12 3 31 5 ...
- BZOJ_1260_[CQOI2007]涂色paint _区间DP
BZOJ_1260_[CQOI2007]涂色paint _区间DP 题意: 假设你有一条长度为5的木版,初始时没有涂过任何颜色.你希望把它的5个单位长度分别涂上红.绿.蓝.绿.红色,用一个长度为5的字 ...
- 矩阵优化dp
链接:https://www.luogu.org/problemnew/show/P1939 题解: 矩阵优化dp模板题 搞清楚矩阵是怎么乘的构造一下矩阵就很简单了 代码: #include < ...
- bzoj 3120 矩阵优化DP
我的第一道需要程序建矩阵的矩阵优化DP. 题目可以将不同的p分开处理. 对于p==0 || p==1 直接是0或1 对于p>1,就要DP了.这里以p==3为例: 设dp[i][s1][s2][r ...
- HDU - 2294: Pendant(矩阵优化DP&前缀和)
On Saint Valentine's Day, Alex imagined to present a special pendant to his girl friend made by K ki ...
- [六省联考2017]组合数问题 (矩阵优化$dp$)
题目链接 Solution 矩阵优化 \(dp\). 题中给出的式子的意思就是: 求 nk 个物品中选出 mod k 为 r 的个数的物品的方案数. 考虑朴素 \(dp\) ,定义状态 \(f[i][ ...
- [CSP-S模拟测试]:涂色游戏(DP+组合数+矩阵快速幂)
题目描述 小$A$和小$B$在做游戏.他们找到了一个$n$行$m$列呈网格状的画板.小$A$拿出了$p$支不同颜色的画笔,开始在上面涂色.看到小$A$涂好的画板,小$B$觉得颜色太单调了,于是把画板擦 ...
随机推荐
- JavaScript学习系列博客_35_JavaScript 正则表达式的使用
正则表达式的使用 先说RegExp对象的一个方法 test() - 使用这个方法可以用来检查一个字符串是否符合正则表达式的规则,如果符合则返回true,否则返回false. 1.用正则表达式来检查一个 ...
- J20航模遥控器开源项目系列教程(三)开发说明 | 想要自己改造程序,扩充功能,怎么实现?
我们的开源宗旨:自由 协调 开放 合作 共享 拥抱开源,丰富国内开源生态,开展多人运动,欢迎加入我们哈~ 和一群志同道合的人,做自己所热爱的事! 项目开源地址:https://github.com/C ...
- Hyperledger Fabric 手动搭建【区块链学习三】
Hyperledger Fabric 手动搭建 前面我们学习了区块链是什么.还有自动搭建学习东西我们就要从简单到深入(入门到放弃),现在自动部署已经跑通了接下来就是手动搭建Fabric 网络可以更好的 ...
- mysql 1215错误 外键建立失败
在Mysql中创建数据表时,经常会遇到问题而失败,其中建立外键有很多细节需要我们去留意,主要有以下几种常见原因. 1. 两个字段的类型或者大小不严格匹配.例如,如果一个是int(10),那么外键也必 ...
- 区块链入门到实战(29)之Solidity – 环境搭建
在线开发环境Remix(推荐) 学习Solidity推荐使用在线开发环境Remix,本教程的例子将使用Remix开发运行. 安装本地编译器 安装 nodejs / npm node官方网站下载node ...
- 4gl游标cursor
游標有多種寫法,一種是報表里常見的 這種寫法呢,先定義一個接受sql語句的變量l_sql,而接受到的語句實際上只是一連串的字符串,還包含了4gl裡面的一些變量.寫好的l_sql裡面之所以有多個分段的雙 ...
- Java I/O体系从原理到应用(非原创)
基础概念 在介绍I/O原理之前,先重温几个基础概念: 1 操作系统与内核 操作系统:管理计算机硬件与软件资源的系统软件内核:操作系统的核心软件,负责管理系统的进程.内存.设备驱动程序.文件和网络系统等 ...
- Windows 下mysqldump备份1045错误解决办法
一.我写的备份脚本如下 set d=%date:~0,4%%date:~5,2%%date:~8,2% C:\mysqldump -uroot -ptest@2018 --all-databases ...
- Laravel ServiceProvider注册过程及简单使用
Laravel ServiceProvider注册过程及简单使用 还记得facade注册流程吗?回顾下 在bootstrap/app.php中返回$app实例后,通过singleton方法绑定了三个实 ...
- IntPtr to bytes
byte[] managedArray = new byte[size]; Marshal.Copy(pnt, managedArray, 0, size);