不努力永远都只能是菜鸡,菜鸡..
这题咋一眼看会觉得很难,但是呢.首先的矩阵大小是hw的,但是他只要求nm的任意加起来为奇数.当然题目似乎没讲只能填1~9的数..
你会发现假如第一个nm的矩阵确认,那么符合条件的填法也是确认了..
因为为了维护奇数,我平移一个数,移进来的数和移出去的数奇偶性一定是一样的,那么问题就变成了,填第一个n*m的矩阵满足各行各列都是奇数的有多少种,当然,后面的也得合法,如此,题目就简单了许多...
代码有注释:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=11,M=(1<<10)+3,T=55;
const int mod=1e9+7;
int odd[N][N],even[N][N],dp[N][M];
//奇数的i行j列'.'填奇数的种数 偶数的i行j列'.'填偶数的种数 在i行状态为j的种数
bool b_odd[N][N],b_even[N][N];
//判断这个位子是不是有奇数/偶数
char s[T];
signed main()
{
int h,w,n,m;
scanf("%lld%lld%lld%lld",&h,&w,&n,&m);//输入
for(int i=0;i<n;i++)
for(int j=0;j<m;j++) odd[i][j]=even[i][j]=1;
for(int i=0;i<h;i++)
{
scanf("%s",s);
for(int j=0;j<w;j++)
{
if(s[j]=='.')
{
odd[i%n][j%m]=odd[i%n][j%m]*5%mod;
even[i%n][j%m]=even[i%n][j%m]*4%mod;
}
else if((s[j]-'0')%2)//有奇数
{
b_odd[i%n][j%m]=true;
}
else//有偶数
{
b_even[i%n][j%m]=true;
}
}
}
//统计完成
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(b_odd[i][j]&b_even[i][j])
{
puts("0");
return 0;
}
//特判无解.
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<(1<<m);j++)//二进制枚举'.'的奇偶
{
int sum=1,flag=0,tag=0;//统计答案,直接判断无解的,间接判断无解
for(int k=0;k<m;k++)
{
if(j&(1<<k))//奇数
{
tag^=1;
sum=sum*odd[i-1][k]%mod;
if(b_even[i-1][k]) {flag=1; break;}
}
else//偶数
{
sum=sum*even[i-1][k]%mod;
if(b_odd[i-1][k]) {flag=1; break;}
}
}
if(flag||!tag) continue;
for(int l=0;l<(1<<m);l++) dp[i][l^j]=(dp[i][l^j]+dp[i-1][l]*sum)%mod;
}
}
printf("%lld\n",dp[n][(1<<m)-1]);
return 0;
}
京公网安备 11010502036488号