bzoj5093: [Lydsy1711月赛]图的价值 第二类斯特林数

Description
“简单无向图”是指无重边、无自环的无向图(不一定连通)。
一个带标号的图的价值定义为每个点度数的k次方的和。
给定n和k,请计算所有n个点的带标号的简单无向图的价值之和。
因为答案很大,请对998244353取模输出。
Input
第一行包含两个正整数n,k(1<=n<=10^9,1<=k<=200000)。

做法:
用第二类斯特林数推公式
题解

关于第二类斯特林数
留坑,有空了好好学一波,但是这些公式要怎么才记得住!
没事,有板子,重点会用!

一个简单的模板我却调了很久,写多项式的能力很差!

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define repd(i,a,b) for(int i=a;i>=b;--i)
#define rvc(i,S) for(int i=0;i<(int)S.size();++i)
#define fore(i,x) for(int i = head[x] ; i ; i = e[i].next)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define lowbit(x) (x&(-x))
using namespace std;
#define maxn 600020

typedef long long ll;
typedef vector <ll> Poly;

const ll mod = 998244353;
const ll G = 3 , gi = 3;
ll ginv;
ll w[2][maxn];

namespace Polygen {
	inline ll add(ll x,ll y){
		x += y;
		if ( x >= mod ) x -= mod;
		return x;
	}
	inline ll sub(ll x,ll y){
		x -= y;
		if ( x < 0 ) x += mod;
		return x;
	}
	inline ll power(ll x,ll y){
		ll res = 1;
		while ( y ){
			if ( y & 1 ) res = res * x % mod;
			x = x * x % mod;
			y >>= 1;
		}
		return res;
	}
	void init(){
		ginv = power(G,mod - 2);
		for (int i = 1; i < (1 << 19); i <<= 1) {
			ll wn = power(gi, (mod - 1) / (i << 1));
			for (int j = 0; j < i; j++) {
				w[1][i + j] = (j ? wn * w[1][i + j - 1] % mod : 1);
			}
			wn = power(gi, mod - 1 - (mod - 1) / (i << 1));
			for (int j = 0; j < i; j++) {
				w[0][i + j] = (j ? wn * w[0][i + j - 1] % mod : 1);
			}
		}
	}	
	void print(const Poly &p){
		cout<<p.size()<<endl;
		rvc(i,p) cout<<p[i]<<" ";
		cout<<endl;
	}
	inline void NTT(Poly &a,int len,int fl) { //预处理原根快了一倍!
		fl = max(0 , fl);
		int i , j , k;
		for (j = 1 , i = ( len >> 1 ) ; j < len; j++) {
			if (j > i) swap(a[i] , a[j]);
			for (k = (len>>1) ; k & i; k >>= 1 ) i ^= k;
			i ^= k;
		}

		for (i = 1; i < len; i <<= 1) {
			for (j = 0; j < len; j += i << 1) {
				for (k = 0; k < i; k++) {
					ll x = a[j + k], y = a[j + k + i] * w[fl][i + k] % mod;
					a[j + k] = add( x , y );
					a[j + k + i] = sub( x , y );
				}
			}
		}
		if (fl == 0) {
			ll inv = power(len , mod-2);
			for (int i = 0; i < len; i++)	a[i] = a[i] * inv % mod;
		}
	}
}

using namespace Polygen;

Poly S,f,g;

int n,k;
ll fac[maxn],inv[maxn],pow2[maxn],fac2[maxn];

void pre(){
	fac[0] = inv[0] = pow2[0] = fac2[0] = 1;
	rep(i,1,k) fac[i] = fac[i - 1] * i % mod , inv[i] = power(fac[i],mod - 2) , pow2[i] = pow2[i - 1] * 2 % mod;
//	cout<<f.size()<<" "<<g.size()<<endl;
	rep(i,1,k) fac2[i] = fac2[i - 1] * (n - i) % mod;
	rep(i,0,k){
		if ( i & 1 ) f[i] = (mod - inv[i]);
		else f[i] = inv[i];
		g[i] = power(i,k) * inv[i] % mod;
	//	cout<<f[i]<<" "<<g[i]<<endl;
	}
}
inline ll C(int n,int m){
	if ( n < m ) return 0;
	return fac2[m] * inv[m] % mod;
}
int main(){
//	freopen("input.txt","r",stdin);

	init();
	scanf("%d %d",&n,&k);
	int len = ceil(log2(k * 2));
	len = 1 << len;
	f.resize(len) , g.resize(len) , S.resize(len);
	pre();
	NTT(f,len,1) , NTT(g,len,1);
	rep(i,0,len - 1) S[i] = f[i] * g[i] % mod;
	NTT(S,len,-1);
	S[0] = 0;
	//	rep(i,0,min(k,100)) cout<<S[i]<<" ";
//	cout<<endl;
	ll ans = 0;
	rep(i,0,min(n - 1,k)){
		ans = (ans + S[i] * fac[i] % mod * C(n - 1,i) % mod * power(2,n - 1 - i)) % mod;
	}
	ans = ans * n % mod * power(2,(ll)(n - 1) * (n - 2) / 2 % (mod - 1)) % mod;
	cout<<ans<<endl;
}

猜你喜欢

转载自blog.csdn.net/weixin_42484877/article/details/83385895