【清華夏令營2016模擬5.31】圖樣

題目

Input
一行兩個正整數,分別表示n和m。

Output
一行一個正整數表示答案。

Sample Input
樣例1:
2 2
樣例2:
10 3

Sample Output
樣例1:
129140165
樣例2:
7008635

Data Constraint
對於30%的數據n*m<=16
對於另外20%的數據m<=4
對於100%的數據n<=50,m<=8

思路

考慮知道點權怎麼求

建出trie,對於trie的每個節點,如果它既有0兒子,又有1兒子,那麼這兩棵子樹分別聯通後,要找一條最小的邊把它們連起來。

於是我們可以枚舉這個節點的深度,再枚舉它的左子樹和右子樹的大小,問題轉換爲:

有x和y個k位二進制數,求它們之間的異或最小值。

設f[x][y][z][u]爲有x和y個k位二進制數,最小值≥u的方案數。

代碼

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int mod = 258280327;

ll power(ll x,ll y) {
	ll s = 1;
	for(; y; y /= 2,x = x * x % mod)
		if(y & 1) s = s * x % mod;
	return s;
}

const int N = 55;

const int M = 260;

int n,m;

ll c[M][M];

ll f[N][N][9][M];

int a2[9];

ll b[N];

void build(int n) {
	for(int i=0; i<=n; i++) {
		c[i][0] = 1;
		for(int j=1; j<=i; j++) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
	}
}

int main()
{
	build(256);
	a2[0]=1; 
	for(int i=1; i<=8; i++) a2[i]=a2[i-1]*2;
	scanf("%d %d",&n,&m);
	for(int i=0; i<=n; i++) for(int j=0; j<=n; j++) for(int k=0; k<=m; k++) if(!i||!j||!k)
	{
		ll s = 1;
		for(int u=1; u<=i+j; u++) s=s*a2[k]%mod;
		for(int u=0; u<a2[k]; u++) f[i][j][k][u]=s;
	}
	for(int i=1; i<=n; i++) for(int j=1; j<=n-i; j++) for(int k=1; k<=m; k++) 
	{
		for(int I=0; I<=i; I++) for(int J=0; J<=j; J++)
		{
			int t=a2[k-1];
			if((I&&J)||((i-I)&&(j-J))) t=0;
			ll xs=c[i][I]*c[j][J]%mod;
			for(int u=0; u<a2[k-1]; u++)
			{
				if(t==0) f[i][j][k][u + t] = (f[i][j][k][u + t] + f[I][J][k - 1][u] * f[i - I][j - J][k - 1][u] % mod * xs) % mod;
				else f[i][j][k][u + t] = (f[i][j][k][u + t] + f[I][j - J][k - 1][u] * f[i - I][J][k - 1][u] % mod * xs) % mod;
			}
		}
		ll s = f[i][j][k][a2[k - 1]];
		for(int u=0; u<a2[k-1]; u++) f[i][j][k][u]=(f[i][j][k][u]+s)%mod;
	}
	ll ans = 0;
	for(int i=1; i<=m; i++) 
	{
		b[0] = 1;
		b[1] = a2[m] - a2[i];
		for(int j=2; j<=n; j++) b[j] = b[j - 1] * b[1] % mod;
		for(int j=1; j<=n; j++) for(int k=1; k<=n-j; k++)
		{
			ll xs = c[n][j] * c[n - j][k] % mod * a2[m - i] % mod * b[n - j - k] % mod;
			ll xs2 = 1;
			for(int u=1; u<=j+k; u++) xs2 = xs2 * a2[i - 1] % mod;
			ans = (ans + xs * a2[i - 1] % mod * xs2) % mod;
			ll s = 0;
			for(int u=1; u<a2[i-1]; u++) s = (s + f[j][k][i - 1][u]) % mod;
			ans = (ans + xs * s) % mod;
		}
	}
	ll v = power(a2[m],n);
	printf("%lld\n",ans * power(v,mod - 2) % mod);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章