分析:
实质上很水的状压DP题。。。。。
因为 ,可以枚举哪些行被消除了,在状压转移删除的列
首先枚举一个 表示要删除哪些行
设 表示前i列已经被消除的行的状态为j,其中 为 的子集
对于当前这一列,如果每一个有位置的行都被j覆盖了,那么就只能直接转移
如果存在一个位置,其没被mask覆盖,那么则必须在这一列选一个:存在于mask中但不存在于j中的点删除掉。
加几个卡常优化也是可以的。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 22
#define MAXM 4096+100
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
bool mp[MAXN][MAXN];
ll mod=100000000;
struct node{
ll lar,mid,sma;
node operator =(int a){
sma=a;
mid=0;
lar=0;
}
node operator +=(const node &a) {
sma=sma+a.sma;
mid=sma/mod+mid+a.mid;
lar=mid/mod+lar+a.lar;
sma%=mod;
mid%=mod;
lar%=mod;
}
node operator *(const node &a){
ll x=sma*a.sma;
ll y=mid*a.sma+sma*a.mid;
ll z=sma*a.lar+mid*a.mid+lar*a.sma;
y+=x/mod;
z+=y/mod;
node res;
res.sma=x%mod;
res.mid=y%mod;
res.lar=z%mod;
return res;
}
bool operator ==(const node &a){
if(sma!=a.sma)
return 0;
if(mid!=a.mid)
return 0;
return lar==a.lar;
}
void print(){
if(lar!=0){
PF("%I64d",lar);
PF("%08I64d",mid);
PF("%08I64d",sma);
}
else if(mid!=0){
PF("%I64d",mid);
PF("%08I64d",sma);
}
else{
PF("%I64d",sma);
}
}
}dp[MAXN][MAXM],fac[MAXN],ans[MAXN],zero;
int n,m;
node solve(int x,int k1){
dp[0][0]=1;
for(int i=0;i<m;i++){
bool flagx=0;
for(int j=x;;j=((j-1)&x)){
dp[i+1][j]=0;
if(j==0)
break;
}
for(int j=x;;j=((j-1)&x)){
if(dp[i][j].sma==0&&dp[i][j].mid==0&&dp[i][j].lar==0){
if(j==0)
break;
continue;
}
flagx=1;
bool flag=0;
int now=0;
for(int k=0;k<n;k++)
if(mp[k][i]==1){
now|=(1<<k);
if((x&(1<<k))==0)
flag=1;
}
if(flag==0&&(now|x)==x)
dp[i+1][j]+=dp[i][j];
for(int k=0;k<n;k++)
if((j&(1<<k))==0&&(x&(1<<k))!=0&&mp[k][i]==1)
dp[i+1][j|(1<<k)]+=dp[i][j];
if(j==0)
break;
}
if(flagx==0)
return zero;
}
return dp[m][x]*fac[k1];
}
bool check(int x,int k1){
int res=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(((1<<i)&x)==0&&mp[i][j]==1)
res|=(1<<j);
return __builtin_popcount(res)<=k1;
}
char s[MAXN];
int main(){
//freopen("k.in","r",stdin);
//freopen("wa.out","w",stdout);
int t,k;
SF("%d",&t);
fac[0]=1;
for(int i=1;i<=12;i++){
node i1;
i1=i;
fac[i]=fac[i-1]*i1;
}
while(t--){
SF("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++)
ans[i].lar=ans[i].mid=ans[i].sma=0;
int ald=0;
for(int i=0;i<n;i++){
SF("%s",s);
for(int j=0;j<m;j++){
mp[i][j]=(s[j]=='Q');
if(mp[i][j]==1)
ald|=(1<<i);
}
}
node las;
las=0;
for(int i=0;i<(1<<n);i++){
int k1=__builtin_popcount(i);
if(k1>k||(i|ald)!=ald||check(i,k1)==0)
continue;
node res=solve(i,k1);
if((las==zero)==0&&(res==zero)==1)
break;
ans[k1]+=res;
}
for(int i=1;i<=k;i++){
ans[i].print();
PF("\n");
}
}
}