【gdoi2018 day2】第二题 滑稽子图

题意:

给出一棵树。设(E)表示边集,(V)表示点集,(S)(V)的一个子集。

(f(S)=|(u,v)|(u,v)in E && uin V && vin V)

(displaystyle sum_{Ssubseteq V}f(S)^k)(998244353)取模的结果。

$nleq100000,kleq 10 $。

还是对二项式定理不是很熟悉啊。

处理这类和的(k)次方问题经常用到二项式定理。

[displaystyle (a+b)^k=sum_{i=0}^kinom{k}{i}a^ib^{k-i} ]

于是对于每个(iin [0,k]),我们都维护(f_{v,i})表示(v)的子树中(displaystyle sum_{Ssubseteq T}f(S)^i)

转移的时候就(k^2)转移就行了。

特别地,我们让(0^0=1),方便转移。

当然也可以用斯特林数

[displaystyle n^m=sum_{i=0}^megin{Bmatrix}m\iend{Bmatrix}inom{n}{i}i! ]

我们有组合恒等式

[displaystyle inom{a+b}{k}=sum_{i=0}^kinom{a}{i}inom{b}{k-i} ]

然后就可以同样的(k^2)

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 100005

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

const ll mod=998244353;
ll ksm(ll t,ll x) {
	ll ans=1;
	for(;x;x>>=1,t=t*t%mod)
		if(x&1) ans=ans*t%mod;
	return ans;
}
int n,m,k;
struct road {
	int to,nxt;
}s[N<<1];
int h[N],cnt;
void add(int i,int j) {s[++cnt]=(road) {j,h[i]};h[i]=cnt;}

ll f[N][2][15];
ll g[2][15],H[2][15];
ll c[15][15];

void dfs(int v,int fr) {
	f[v][0][0]=f[v][1][0]=1;
	for(int i=h[v];i;i=s[i].nxt) {
		int to=s[i].to;
		if(to==fr) continue ;
		dfs(to,v);
		memset(g,0,sizeof(g));
		for(int j=0;j<=k;j++) {
			for(int q=0;q<=k-j;q++) {
				(g[0][j+q]+=c[j+q][j]*f[v][0][j]%mod*(f[to][0][q]+f[to][1][q]))%=mod;
				(g[1][j+q]+=c[j+q][j]*f[v][1][j]%mod*f[to][0][q])%=mod;
			}
		}
		memset(H,0,sizeof(H));
		for(int j=0;j<=k;j++) {
			for(int q=0;q<=k-j;q++) {
				(H[1][j+q]+=c[j+q][j]*f[v][1][j]%mod*f[to][1][q])%=mod;
			}
		}
		memcpy(f[v],g,sizeof(g));
		for(int j=k;j>=1;j--) 
			for(int q=0;q<j;q++) (H[1][j]+=c[j][q]*H[1][q])%=mod;
		for(int j=0;j<=k;j++) (f[v][1][j]+=H[1][j])%=mod;
	}
}

int main() {
	n=Get(),m=Get(),k=Get();
	for(int i=0;i<=k;i++)
		for(int j=0;j<=i;j++)
			c[i][j]=(!j||i==j)?1:(c[i-1][j-1]+c[i-1][j])%mod;
	int a,b;
	for(int i=1;i<=m;i++) {
		a=Get(),b=Get();
		add(a,b),add(b,a);
	}
	dfs(1,0);
	cout<<(f[1][0][k]+f[1][1][k])%mod;
	return 0;
}

原文地址:https://www.cnblogs.com/hchhch233/p/10516992.html