Atcoder 题面传送门 & 洛谷题面传送门

首先我们考虑设 \(dp_{i,j}\) 表示对于一个 \(i\times j\) 的网格,其每行都至少有一个黑格的合法的三元组 \((A,B,C)\) 的个数,那么对于原来的 \(n\times m\) 的网格,如果其存在黑格的行的集合不同,那么三元组 \((A,B,C)\) 肯定不同,因此我们可以直接枚举有多少行存在黑格来计算答案,即 \(ans=\sum\limits_{i=0}^n\dbinom{n}{i}dp_{i,m}\),因此我们只需求出 \(dp_{i,j}\) 即可求出答案。

接下来考虑怎样求出 \(dp_{i,j}\),首先边界条件肯定是 \(dp_{i,1}=1\),因为必须每格都染黑。接下来考虑转移,转移 \(dp_{i,j}\) 时,我们就枚举这个 \(i\times j\) 的矩阵前 \(j-1\) 列组成的子矩阵中,有多少行存在黑格,我们记这个数为 \(k\),那么可以这样从 \(dp_{k,j-1}\) 转移到 \(dp_{i,j}\):

  • 如果 \(k=i\),由于这个情况比较特殊,故我们单独将其拎出来。由于前 \(j-1\) 列组成的子矩阵中每行都存在黑格,故每行的 \(A_i\) 都是不为 \(0\) 的,加入第 \(j\) 列后 \(A\) 序列肯定不会发生变化,因此我们只需考虑 \(B,C\) 序列的变化即可。显然所有满足 \(x\le y\) 可能的二元组 \((x,y)\) 及 \((i+1,0)\)(这一列没有黑格的情况)都可以成为合法的 \((B_j,C_j)\),总个数为 \(1+j+\dbinom{j}{2}\),因此我们有 \(dp_{i,j}\leftarrow dp_{i,j-1}(1+j+\dbinom{j}{2})\)
  • 如果 \(k\lt i\),那么显然会出现一些本来没有黑格的行出现了黑格,对于这些行而言,其 \(A\) 值肯定就是 \(j\),而那些本来就存在黑格的行的 \(A\) 值肯定不会变,因此我们还是不用考虑 \(A\) 值的变化,考虑哪些行新出现了黑格及 可能的 \(B_j,C_j\) 即可,一个非常 naive 的想法是直接用组合数计算新出现黑格的行可能的情况,即 \(dp_{i,j}\leftarrow dp_{k,j-1}\dbinom{i}{i-k}\),但是这显然是错误的,因为它没有考虑到 \(B,C\) 的变化,比方说对于一个 \(5\times 2\) 的矩阵,第一列 \(1,3\) 为黑格,第二列 \(2,4,5\) 行为黑格的情况,与第一列 \(1,3\) 为黑格,第二列 \(1,2,4,5\) 行为黑格的情况,虽然对于第二列而言,新多出黑格的行的集合是相同的,但是显然在两种情况中 \(B_2\) 的值是不同的,因此它们也应被视为不同的情况。怎么解决呢?我们考虑最上方的黑格正上方的白格,即 \(B_j-1\);以及最下方的黑格正下方的白格,即 \(C_j+1\),这二者与新多出的 \(i-k\) 行会形成 \(i-k+2\) 个数 \(p_1,p_2,\cdots,p_{i-k+2}\),显然这 \(i-k+2\) 个数都在 \([0,i+1]\) 中,它们两两互不相同,且 \(B_j-1\) 肯定是这 \(i-k+2\) 中的最小值,\(C_j+1\) 肯定是这 \(i-k+2\) 中的最大值。又对于两种第 \(j\) 列的染色方案,它们被视作不同的染色方案当且仅当这 \(i-k+2\) 个数组成的集合 \(\{p_1,p_2,\cdots,p_{i-k+2}\}\) 不同,因此我们只需统计有多少个合法的集合 \(\{p_1,p_2,\cdots,p_{i-k+2}\}\) 即可,这个方案数显然是 \(\dbinom{i+2}{i-k+2}\),因此我们有转移 \(dp_{i,j}\leftarrow dp_{k,j-1}\dbinom{i+2}{i-k+2}\)

故我们有 \(dp_{i,j}=dp_{i,j-1}(1+j+\dbinom{j}{2})+\sum\limits_{k=0}^{i-1}dp_{k,j-1}\dbinom{i+2}{i-k+2}\),这样暴力转移是 \(\mathcal O(n^2m)\) 的,无法通过,不过注意到后面一个 \(\sum\) 可以变形为 \(\sum\limits_{k=0}^{i-1}dp_{k,j-1}\dfrac{(i+2)!}{k!(i-k+2)!}=(i+2)!\sum\limits_{k=0}^{i-1}\dfrac{dp_{k,j-1}}{k!}\dfrac{1}{(i-k+2)!}\),这显然是一个卷积的形式,因此 NTT 优化即可,TC 即可降到 \(\mathcal O(nm\log n)\)。

const int MAXN=8000;
const int MAXM=200;
const int MAXP=1<<14;
const int MOD=998244353;
const int pr=3;
const int ipr=(MOD+1)/3;
int qpow(int x,int e){
int ret=1;
for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
return ret;
}
int n,m,dp[MAXN+5][MAXM+5],ans=0;
int fac[MAXN+5],ifac[MAXN+5];
void init_fac(int n){
for(int i=(fac[0]=ifac[0]=ifac[1]=1)+1;i<=n;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i-1]*ifac[i]%MOD;
}
int binom(int n,int k){return 1ll*fac[n]*ifac[k]%MOD*ifac[n-k]%MOD;}
int rev[MAXP+5];
void NTT(vector<int> &a,int len,int type){
int lg=31-__builtin_clz(len);
for(int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
for(int i=0;i<len;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int i=2;i<=len;i<<=1){
int W=qpow((type<0)?ipr:pr,(MOD-1)/i);
for(int j=0;j<len;j+=i){
int w=1;
for(int k=0;k<(i>>1);k++,w=1ll*w*W%MOD){
int X=a[j+k],Y=1ll*a[(i>>1)+j+k]*w%MOD;
a[j+k]=(X+Y)%MOD;a[(i>>1)+j+k]=(X-Y+MOD)%MOD;
}
}
}
if(type==-1){
int iv=qpow(len,MOD-2);
for(int i=0;i<len;i++) a[i]=1ll*a[i]*iv%MOD;
}
}
vector<int> conv(vector<int> a,vector<int> b){
int LEN=1;while(LEN<a.size()+b.size()) LEN<<=1;
a.resize(LEN,0);b.resize(LEN,0);NTT(a,LEN,1);NTT(b,LEN,1);
for(int i=0;i<LEN;i++) a[i]=1ll*a[i]*b[i]%MOD;
NTT(a,LEN,-1);return a;
}
int main(){
scanf("%d%d",&n,&m);init_fac(n+2);
for(int i=0;i<=n;i++) dp[i][1]=1;
for(int j=2;j<=m;j++){
vector<int> a(n+1),b(n+1);
for(int i=1;i<=n;i++) a[i]=ifac[i+2];
for(int i=0;i<=n;i++) b[i]=1ll*ifac[i]*dp[i][j-1]%MOD;
a=conv(a,b);
for(int i=0;i<=n;i++){
dp[i][j]=1ll*(1+i+binom(i,2))*dp[i][j-1]%MOD;
dp[i][j]=(dp[i][j]+1ll*fac[i+2]*a[i])%MOD;
}
} for(int i=0;i<=n;i++) ans=(ans+1ll*binom(n,i)*dp[i][m])%MOD;
printf("%d\n",ans);
return 0;
}

Atcoder Grand Contest 021 F - Trinity(dp+NTT)的更多相关文章

  1. Atcoder Grand Contest 033 D - Complexity(dp)

    Atcoder 题面传送门 & 洛谷题面传送门 首先 \(n^5\) 的暴力非常容易想,设 \(dp_{a,b,c,d}\) 表示以 \((a,b)\) 为左上角,\((c,d)\) 为右下角 ...

  2. AtCoder Grand Contest 031 B - Reversi(DP)

    B - Reversi 题目链接:https://atcoder.jp/contests/agc031/tasks/agc031_b 题意: 给出n个数,然后现在你可以对一段区间修改成相同的值,前提是 ...

  3. Atcoder Grand Contest 038 F - Two Permutations(集合划分模型+最小割)

    洛谷题面传送门 & Atcoder 题面传送门 好久前做的题了--今天偶然想起来要补个题解 首先考虑排列 \(A_i\) 要么等于 \(i\),要么等于 \(P_i\) 这个条件有什么用.我们 ...

  4. Atcoder Grand Contest 001 F - Wide Swap(拓扑排序)

    Atcoder 题面传送门 & 洛谷题面传送门 咦?鸽子 tzc 来补题解了?奇迹奇迹( 首先考虑什么样的排列可以得到.我们考虑 \(p\) 的逆排列 \(q\),那么每次操作的过程从逆排列的 ...

  5. AtCoder Grand Contest 021完整题解

    提示:如果公式挂了请多刷新几次,MathJex的公式渲染速度并不是那么理想. 总的来说,还是自己太弱了啊.只做了T1,还WA了两发.今天还有一场CodeForces,晚上0点qwq... 题解还是要好 ...

  6. AtCoder Grand Contest 012 B - Splatter Painting(dp)

    Time limit : 2sec / Memory limit : 256MB Score : 700 points Problem Statement Squid loves painting v ...

  7. AtCoder Grand Contest 021

    A - Digit Sum 2 Time limit : 2sec / Memory limit : 256MB Score : 300 points Problem Statement Find t ...

  8. 【Atcoder Grand Contest 011 F】Train Service Planning

    题意:给\(n+1\)个站\(0,\dots,n\),连续的两站\(i-1\)和\(i\)之间有一个距离\(A_i\),其是单行(\(B_i=1\))或双行(\(B_i=2\)),单行线不能同时有两辆 ...

  9. AtCoder Grand Contest 032-B - Balanced Neighbors (构造)

    Time Limit: 2 sec / Memory Limit: 1024 MB Score : 700700 points Problem Statement You are given an i ...

随机推荐

  1. 【UE4 C++ 基础知识】<8> Delegate 委托

    概念 定义 UE4中的delegate(委托)常用于解耦不同对象之间的关联:委托的触发者不与监听者有直接关联,两者通过委托对象间接地建立联系. 监听者通过将响应函数绑定到委托上,使得委托触发时立即收到 ...

  2. mysql的一些配置操作

    mysql的一些配置操作 一.背景 二.mysql配置 三.慢查询日志 1.命令行临时生效 2.配置文件修改永久生效 3.慢查询日志解释 4.mysqldumpdlow查看慢查询日志 四.查看索引为何 ...

  3. 2021.6.17考试总结[NOIP模拟8]

    T1 星际旅行 其实就是求两条只走一遍的边的方案数. 考场上第一眼就感觉不可做,后来画了几个图,发现好像只要两个边是相连的就可以只走一遍,居然还真拿了30.. 其实是一道欧拉路的题,把每条非自环的边看 ...

  4. NB-IoT的DRX、eDRX、PSM三个模式怎么用?通俗解释,看完就懂!

    面我们讲了不少NB-IOT的应用.软件和硬件设计的变动. (链接在文章末尾). 今天讲讲NB-IoT的三大模式,在各种物联网和智能硬件场景中的使用方法 DRX.eDRx.PSM是什么? DRX虽然叫做 ...

  5. vsftpd 编译安装 及 隐藏版本号

    环境:Redhat Enterprise Linux AS 4.0 update2(i386) 不提示,均表示以root权限执行. [注:]//为注释符,如"// 建立MySQL组" ...

  6. 应对gitee容量超限. 保留star/fork/评论

    应对gitee容量超限 进入企业版,"管理"-"仓库管理",点"清空仓库". 在E:\gitee目录上右击,"git bash h ...

  7. Arthas在线java进程诊断工具 在线调试神器

    tag: java 诊断 堆栈 在线调试 耗时 死锁 arthas 阿里巴巴 Arthas (阿尔萨斯) Arthas 是 Alibaba 开源的Java诊断工具,深受开发者喜爱. 官网文档:http ...

  8. "迷途"的野指针,都快找不着北了

    指针,C语言开发者表示很淦,指针的使用,很多人表示不敢直面ta,不像Java一样,有垃圾自动回收功能,我们不用担心那么多内存泄漏等问题,那C语言里边呢,指针又分为了"野指针",&q ...

  9. 【Go语言学习笔记】函数做参数和闭包

    函数做参数 在Go语言中,函数也是一种数据类型,我们可以通过type来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型.类似于重写(同名覆盖). 回调函数:函数有一个参数是函数类型,这个 ...

  10. Java使用assert断言

    Java1.4后新增assert关键字 Idea中开启assert断言 使用 assert boolean表达式 assert boolean表达式 : 错误提示信息 例子 public static ...