题意:
给你一个有向无环图,从1出发,每一个点都会呆一天,假设这条路连着k条边,那么第二天有1/(k+1)的概率再呆一天,或者1/(k+1)的概率沿着某一条边走。第三天他必须沿着某一条边走。走一条边的时间是一天。他会在无路可走的情况下结束旅行,最后一个位置他会呆2天。问你他旅行的天数的期望。
题解:
讨厌的期望题。
首先确定是dfs,再确定是回溯的时候做期望,因为向下的时候不好做,还要传概率,回溯的时候做的话就可以直接把后面的期望乘上概率再加上这一次做的决定乘这一次的概率即可。为了速度我用了快读,去掉亦可。
那么我们假设下一个点的期望是x,那么已知走任意一条边的时间为1,且至少在这个点呆一天,所以这个2我们无论从哪个地方走过来都是必须要加的,那么就可以在return之前再加。那么到了这个点我们就可以假设直接走或者呆一天再走,直接走的概率是x*k/(k+1)/k(也就是先从走不走这两种情况选出走的情况,再选走哪条路),呆一天的概率是x*1/(k+1)/k。
注意这时候我直接交会出现什么问题
TLE7
如果每个点只走一遍花的时间是O(n),且cf不会爆栈,那么就是有些点走了很多遍,那么我们只需要记录上一次这个点的期望是多少即可,用aa来记录。于是就变成了记忆化搜索。
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define ll long long
namespace fastIO {
#define BUF_SIZE 100000
//fread -> read
bool IOerror = 0;
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if(p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline void read(int &x) {
char ch;
while(blank(ch = nc()));
if(IOerror) return;
for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
}
#undef BUF_SIZE
};
using namespace fastIO;
const ll mod=998244353;
const int N=1e5+5;
ll inv[N];
struct node
{
int to,next;
}e[N];
int cnt,head[N];
void add(int x,int y)
{
e[cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt++;
}
void init(){
inv[1] = 1;
for(int i = 2; i <= N-1 ; i++)
inv[i] = ( mod - mod / i ) * inv[ mod % i ] % mod;
inv[0] = 1;
memset(head,-1,sizeof(head));
}
ll son[N];
ll aa[N];
ll dfs(int x)
{
if(aa[x])
return aa[x];
ll ans=0;
for(int i=head[x];~i;i=e[i].next)
{
int ne=e[i].to;
ll s=dfs(ne);
ans=(ans+(s*son[x]%mod*inv[son[x]+1]%mod)*inv[son[x]]%mod+((s+1)*inv[son[x]])%mod*inv[son[x]+1]%mod)%mod;
}
ans=(ans+2)%mod;
aa[x]=son[x]?ans:2;
if(!son[x])
return 2;
return ans;
}
int main()
{
init();
int t;
read(t);
while(t--)
{
cnt=0;
int n,m,x,y;
read(n),read(m);
for(int i=1;i<=m;i++)
read(x),read(y),add(x,y),son[x]++;
printf("%lld\n",dfs(1));
for(int i=0;i<=n;i++)
son[i]=aa[i]=0,head[i]=-1;
}
return 0;
}