noip2018 10.31 T1

T1

首先,考虑到,所要求的期望就是 可行的方案数比总方案数

很显然,对于一个点,其他点的选择对它没有影响,所以总方案数即为 $n^n$

下面,考虑可行的方案数。

经过打表,可以发现,打表什么规律都找不到。

所以我们考虑递推。

对于第n个点,有两种情况:

​ ①前(n-1)个点已经可行,则第n个点应该形成自环。 $F[n]+=F[n-1]$

​ ②前(n-1)个点中有(n-2)个点已经可行,则第n个点应该和剩下的点形成环。剩下的点有(n-1)个可能。 $F[n]+=(n-1)*F[n-2]$

所以我们得到递推式:

​ $F[n]=F[n-1]+(n-1)*F[n-2] $

然后,先预处理出 $F[n]$,然后快速幂求出 $n^n$,用exgcd求出它的逆元,膜膜膜即可。

#include<bits/stdc++.h>
#define ll long long
#define MOD 998244353
using namespace std;
int read(){
	int data=0,w=1;char ch=0;
	while(!isdigit(ch)){if(ch=='-') w=-1;ch=getchar();}
	while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
	return data*w;
}
ll i,j,k,l,m,n,x,y,t,ans,summ,f[600010];
ll ksm(ll a,ll b){
	ll ans=1;
	while(b){
		if(b&1) ans=ans*a%MOD;
		b>>=1; a=a*a%MOD;
	}
	return ans;
}
void exgcd(ll a,ll b){
	if(!b) x=1,y=0;
	else{
		exgcd(b,a%b);
		ll xx=x,yy=y;
		x=yy;
		y=xx-a/b*yy;
	}
}
int main(){
	t=read();
	f[1]=1;f[2]=2;
	for(i=3;i<=500003;++i) f[i]=(f[i-1]+((i-1)*f[i-2]%MOD))%MOD;
	while(t--){
		n=read();
		exgcd(ksm(n,n),MOD);
		while(x<0) x+=MOD;
		ans=f[n]*x%MOD;
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2018-10-31 20:00  lybrain  阅读(83)  评论(0)    收藏  举报