【JZOJ 省選模擬】6707.異或樹(xor)

題目

Description
在這裏插入圖片描述

Input
在這裏插入圖片描述

Output
在這裏插入圖片描述

Sample Input
樣例輸入1:
2 2 998244353
樣例輸入2:
10 3 998244353

Sample Output
樣例輸出1:
24
樣例輸出2:
579443574

Data Constraint
在這裏插入圖片描述

思路

考慮知道點權怎麼求

建出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 N=57,M=1<<9;
ll mod;
ll power(ll x,ll t)
{
	ll b=1;
	while(t)
	{
		if(t&1) b=b*x%mod;
		x=x*x%mod; t>>=1;
	}
	return b;
}
int n,m,_2[10];
ll c[M][M],p[N][N][10][M],b[N];
void init(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()
{
	freopen("xor.in","r",stdin); freopen("xor.out","w",stdout);
	scanf("%d%d%d",&n,&m,&mod);
	init(1<<8);
	_2[0]=1; 
	for(int i=1; i<=8; i++) _2[i]=_2[i-1]*2;
	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 w=1; w<=i+j; w++) s=s*_2[k]%mod;
		for(int w=0; w<_2[k]; w++) p[i][j][k][w]=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=_2[k-1];
			if((I&&J)||((i-I)&&(j-J))) t=0;
			ll yjy=c[i][I]*c[j][J]%mod;
			for(int w=0; w<_2[k-1]; w++)
			{
				if(t==0) p[i][j][k][w+t]=(p[i][j][k][w+t]+p[I][J][k-1][w]*p[i-I][j-J][k-1][w]%mod*yjy)%mod;
				else p[i][j][k][w+t]=(p[i][j][k][w+t]+p[I][j-J][k-1][w]*p[i-I][J][k-1][w]%mod*yjy)%mod;
			}
		}
		ll s=p[i][j][k][_2[k-1]];
		for(int w=0; w<_2[k-1]; w++) p[i][j][k][w]=(p[i][j][k][w]+s)%mod;
	}
	ll ans=0;
	for(int i=1; i<=m; i++) 
	{
		b[0]=1;
		b[1]=_2[m]-_2[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 yjy=c[n][j]*c[n-j][k]%mod*_2[m-i]%mod*b[n-j-k]%mod;
			ll yjy2=1;
			for(int w=1; w<=j+k; w++) yjy2=yjy2*_2[i-1]%mod;
			ans=(ans+yjy*_2[i-1]%mod*yjy2)%mod;
			ll s=0;
			for(int w=1; w<_2[i-1]; w++) s=(s+p[j][k][i-1][w])%mod;
			ans=(ans+yjy*s)%mod;
		}
	}
	printf("%lld\n",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章