dp Code QBXT Test Ⅲ T2

题意:有多少个 N M N *M 的矩阵满足:其所有数字都是 K K 2 2 进制数,且每一行每一列的或都是 2 K 1 2^K-1

首先对于二进制的题很大一部分是逐位处理,因为各二进制位之间互不影响,首先我们注意到 K K 是没有意义的, 我们只要求出 N M N * M 0 1 0-1 矩阵有多少种方案使得每行每列的或都是 1 1 即可,记这个答案为 a n s ans' 的话, 最后答案即为 a n s = a n s K ans=ans'^K

我们设 d p [ i ] [ j ] dp[i][ j] 表示前 i i 行有 j j 列或为 1 1 ,那么 d p [ i ] [ j ] dp[i][ j] 转移到下一行时, 能转移到 d p [ i + 1 ] [ k ]   ,   ( k j ) dp[i+1][k]\ ,\ (k≥j)

k = j k=j 时, 意味着在 i + 1 i+1 行上所有前 i i 行为 0 0 位置是 0 0 , 否则一定会出现新的列或为 1 1 ,而第 i + 1 i+1 行剩下 j j 列可以随便放,但要注意不能全放 0 0 ,排除这种情况,方程即为 d p [ i + 1 ] [ j ] + = d p [ i ] [ j ] ( 2 j 1 ) dp[i+1][ j]+=dp[i][j]*(2^j-1)

k > j k>j 时, 意味着 i + 1 i+1 行在前 i i 行为 0 0 的位置上有 k j k-j 列是1,此时第 i + 1 i +1 行剩下 j j 列可以随便放(剩下 j j 列全是 0 0 也可以), 方程 d p [ i + 1 ] [ k ] + = d p [ i ] [ j ] 2 j C k j m j 为dp[i+1][k]+=dp[i][j]*2^j*C^{m-j}_{k-j} 。预处理组合数和 2 2 i i 次幂,最后用快速幂即可。

d p dp 的初值就是在第一行时从 m m 列中选 i i 位为 1 1 的方案数即 d p [ 1 ] [ i ] = C i m dp[1][i]=C^m_i

```#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int mod=1e9+7;
int n,m,kk,t;
ll c[55][55],dp[55][55],pow_2[55];
ll ksm(ll q,ll w)
{
	ll h=1;
	while(w)
	{
		if(w&1)
			h=h*q%mod;
		q=q*q%mod;
		w>>=1;
	}
	return h;
}
int main()
{
	cin>>t;
	pow_2[0]=1;
	for(int i=1;i<=50;++i)
		pow_2[i]=(pow_2[i-1]%mod*2%mod)%mod;
	for(int i=1;i<=50;++i)
	{
		c[i][i]=1;
		c[i][0]=1;
	}
	for(int i=1;i<=50;++i)
		for(int j=i+1;j<=50;++j)
			c[j][i]=(c[j-1][i]%mod+c[j-1][i-1]%mod)%mod;
	while(t--)
	{
		cin>>n>>m>>kk;		
		memset(dp,0,sizeof(dp));
        for(int i=0;i<=m;i++)
            dp[1][i]=c[m][i];
		for(int i=1;i<=n;++i)
			for(int j=1;j<=m;++j)
			{
				dp[i+1][j]=(dp[i+1][j]%mod+(dp[i][j]%mod*(pow_2[j]-1)%mod)%mod)%mod;
				for(int k=j+1;k<=m;++k)
					dp[i+1][k]=(dp[i+1][k]%mod+(dp[i][j]%mod*c[m-j][k-j]%mod*pow_2[j]%mod)%mod)%mod;
			}
		cout<<ksm(dp[n][m],kk)<<endl;		
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/wddwjlss/article/details/83412414