P8189 [USACO22FEB] Redistributing Gifts G题解
令
只需考虑如何求出将其连成一个置换环的方案数。
暴力的 dp 就是设
枚举下一个元素,实时判断能不能转移到以及有没有构成环即可。此时复杂度为
注意到可以去掉起始点这一维,因为我们可以钦定集合
所以设
对于每一个集合
复杂度为
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn=19,maxm=1<<18;
int n,Q,s[maxn];
ll dp[maxm][maxn],g[maxm],h[maxm];
char c[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=0;i<n;i++){
bool flag=0;
for(int j=0;j<n;j++){
int x;
cin>>x;
x--;
if(!flag){
s[i]|=(1<<x);
}
if(x==i) flag=1;
}
}
for(int i=0;i<n;i++){
dp[1<<i][i]=1;
}
for(int i=1;i<(1<<n);i++){
int p=__lg(i&(-i));
for(int j=p;j<n;j++){
if(dp[i][j]){
for(int k=p+1;k<n;k++){
if(!(i&(1<<k)) and s[j]&(1<<k)){
dp[i|(1<<k)][k]+=dp[i][j];
}
}
}
}
}
for(int i=1;i<(1<<n);i++){
for(int j=0;j<n;j++){
int p=__lg(i&(-i));
if(s[j]&(1<<p)){
g[i]+=dp[i][j];
}
}
}
h[0]=1;
for(int i=1;i<(1<<n);i++){
for(int j=i;j;j=(j-1)&i){
if(j&(i&(-i))){
h[i]+=g[j]*h[i^j];
}
}
}
cin>>Q;
while(Q--){
cin>>c;
int ans=0;
for(int i=0;i<n;i++){
if(c[i]=='H') ans|=(1<<i);
}
cout<<h[ans]*h[((1<<n)-1)^ans]<<"\n";
}
return 0;
}