题解:P11765 「KFCOI Round #1」回首
P11765 题解
题目描述不说了。
一开始觉得很像我之前做过的一道拆贡献的题,那题 \(n\le 10^5\),而这题竟然只到 \(200\),必有蹊跷。
发现对于第 \(i\) 次的操作,所有转移只和第 \(i-1\) 次有关,而 \(n\) 又如此小,考虑矩阵快速幂。
对于矩阵快速幂,可以参考我的学习笔记:再谈矩阵快速幂。
考虑设状态矩阵,设 \(i\) 号点的权值为 \(a_i\)。
发现状态矩阵必须包含三种信息,分别是每个点的权值、当前进行到多少轮和轮次自增量 \(1\)。
所以考虑构造一个一行 \(n+2\) 列的状态矩阵如下:
然后考虑构造转移矩阵,设为 \(fac\)。接下来描述可能比较抽象,建议结合下文的矩阵结果一起看。
首先因为状态矩阵是 \(1\times (n+2)\) 的,所以转移矩阵的大小必然是 \((n+2)\times (n+2)\) 的。
观察转移式子,发现每一次操作中,所有 \(a_i\) 都得乘上 \(k_i\)。所以对于 \(1\le i\le n\),\(fac_{i,i}=k_i\)。
然后考虑处理边。
显然对于一条 \(u\rightarrow v\) 的边,\(v\) 会在转移中加上上个阶段 \(u\) 的权值。
令 \(c_{i,j}\) 表示是否存在一条 \(i\rightarrow j\) 的边。
结合矩阵乘法计算公式,故 \(fac_{u,v}=1\)。这里不懂可以自己手玩一下样例。
然后考虑构造转移矩阵中更新 \(t\) 的部分。显然只要令 \(t\leftarrow t+1\),即 \(fac_{n+2,n+2}=fac_{n+2,n-1}=fac_{n+1,n+1}=1\) 即可。
然后考虑没有入度的点需要加 \(t\) 的问题。
考虑若点 \(i\) 没有入度,则 \(fac_{n+1,i}=1\),反之为 \(0\)。
这样若没有入度则加上 \(t\),反之不加。
然后没有提到的其余地方全部填 \(0\) 即可。
所以转移矩阵就被我们构造出来了,设 \(g_i\) 表示点 \(i\) 是否没有入度:
然后就是简单的代码环节了,不懂的请看代码理解。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ljl;
const ljl Mod=998244353;
const int N=105,M=305;
int n,m,cnt_e,ehead[N],deg[N];
ljl T,k[N],g[N][N];
bool ccc[N];
struct MTX{
ljl v[N][N];
MTX(int o)
{
memset(v,0,sizeof(v));
for(int i=1;i<N;++i)v[i][i]=o;
}
}bs(1),f(0),fac(0);
MTX operator * (MTX a,MTX b)
{
MTX ans(0);
for(int i=1;i<=n+2;++i)
for(int j=1;j<=n+2;++j)
for(int k=1;k<=n+2;++k)
ans.v[i][j]=(ans.v[i][j]+a.v[i][k]*b.v[k][j]%Mod)%Mod;
return ans;
}
MTX qpow(MTX a,ljl k)
{
MTX ans(1);
while(k)
{
if(k&1)ans=ans*a;
a=a*a;k>>=1;
}return ans;
}
void printfac()
{
for(int i=1;i<=n+2;++i)
{
for(int j=1;j<=n+2;++j)
cout<<fac.v[i][j]<<' ';
cout<<'\n';
}
return;
}
void outf()
{
for(int i=1;i<=n;++i)
cout<<f.v[1][i]<<' ';
cout<<'\n';
return;
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>m>>T;
for(int i=1;i<=n;++i)cin>>k[i];
for(int i=1,u,v;i<=m;++i)
{
cin>>u>>v;
g[u][v]=1;ccc[v]=1;
}
for(int i=1;i<=n;++i)fac.v[i][i]=k[i];
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(i!=j)
fac.v[i][j]=g[i][j];
fac.v[n+2][n+2]=1;fac.v[n+2][n+1]=1;fac.v[n+1][n+1]=1;
for(int i=1;i<=n;++i)
fac.v[n+1][i]=(ccc[i]^1);
f.v[1][n+2]=1;f.v[1][n+1]=1;
fac=qpow(fac,T);f=f*fac;
outf();
return 0;
}

浙公网安备 33010602011771号