洛谷 P6154 游走
洛谷 P6154 游走
题目背景
zbw 在 B 城游走。
题目描述
B 城可以看作一个有 nn 个点 mm 条边的有向无环图。可能存在重边。
zbw 在 B 城随机游走,他会随机选择一条路径,选择所有路径的概率相等。路径的起点和终点可以相同。
定义一条路径的长度为经过的边数,你需要求出 zbw 走的路径长度的期望,答案对 998244353998244353 取模。
输入格式
第一行两个整数 n,mn,m。
接下来 mm 行,每行两个整数 x,yx,y,表示存在一条从 xx 到 yy 的有向边。
输出格式
一行一个整数,表示答案对 998244353998244353 取模后的值。
题解:
暴力思路:
从每个点开始全图遍历,累加出所有路径条数和路径长度和,两者相除求逆元即是答案。
开Longlong。
目标40pts,实测 pts。
代码:
#include<cstdio>
#define int long long
using namespace std;
const int maxn=1e5+10;
const int maxm=7*1e5+10;
const int tt=5*1e6;
const int mod=998244353;
int n,m,cnt,tmp;
int tot,to[maxm],nxt[maxm],head[maxn];
int inv[tt];
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x,int dep)
{
cnt++;
tmp+=dep;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
dfs(y,dep+1);
}
}
signed main()
{
scanf("%lld%lld",&n,&m);
inv[1]=1;
for(int i=2;i<=tt;i++)
inv[i]=((mod-mod/i)*inv[mod%i])%mod;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%lld%lld",&x,&y);
add(x,y);
}
for(int i=1;i<=n;i++)
dfs(i,0);
int ans=(tmp*inv[cnt])%mod;
printf("%lld\n",ans);
return 0;
}
正解记忆化?本来以为是什么期望DP+拓排之类的小神题(当然对于学弟来讲是水题)。结果正解就是暴搜+记忆化优化。
怀疑人生。
逆元没有必要拿线性求逆元,因为998244353是质数,所以逆元直接就是\(a^{p-2}\),快速幂即可。
代码:
#include<cstdio>
#define int long long
using namespace std;
const int maxn=1e5+10;
const int maxm=7*1e5+10;
const int tt=5*1e6;
const int mod=998244353;
int n,m,cnt,tmp,ans;
int tot,to[maxm],nxt[maxm],head[maxn];
int f[maxn],g[maxn];
//f[i]表示以i为起点的路径条数,g[i]表示以i为起点的路径总长
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x)
{
if(f[x])
return;
f[x]=1;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
dfs(y);
f[x]=(f[x]+f[y])%mod;
g[x]=(g[x]+f[y]+g[y])%mod;
}
}
int qpow(int a,int b)
{
int ret=1;
while(b)
{
if(b&1)
ret=(ret*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return ret%mod;
}
signed main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%lld%lld",&x,&y);
add(x,y);
}
for(int i=1;i<=n;i++)
if(!f[i])
dfs(i);
for(int i=1;i<=n;i++)
{
cnt=(cnt+f[i])%mod;
tmp=(tmp+g[i])%mod;
}
ans=(tmp%mod*qpow(cnt,mod-2)%mod)%mod;
printf("%lld\n",ans);
return 0;
}