比赛 |
round 2『计协冻梨桐难霍』 |
评测结果 |
AAAAAAAAAAAAAAAAAA |
题目名称 |
交换礼物 |
最终得分 |
100 |
用户昵称 |
darkMoon |
运行时间 |
3.748 s |
代码语言 |
C++ |
内存使用 |
36.86 MiB |
提交时间 |
2024-11-22 08:17:21 |
显示代码纯文本
#include<bits/stdc++.h>
#define int long long
using namespace std;
auto mread = [](){int x;scanf("%lld", &x);return x;};
const int N = 25, M = 270005;
int n = mread(), a[N][N], belong[N][N], f[M][N][2];
// f_now_i 表示 now 状态里面的礼物可以重新分配,可分配的奶牛中最靠右的奶牛分到的礼物是 i
// 同时最右面的奶牛受/不受限制
signed main(){
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
cin >> a[i][j];
belong[i][a[i][j]] = j;
}
}
f[0][0][0] = f[0][0][1] = 1;
for(int i = 1; i <= n; i ++){
f[1 << i - 1][i][0] = f[1 << i - 1][i][1] = 1;
}
int m = 1 << n;
for(int i = 2; i <= n; i ++){
for(int now = 0; now < m; now ++){
if(__builtin_popcountll(now) == i){
int p;
for(int j = n; j >= 1; j --){
if(now & (1 << j - 1)){
p = j;
break;
}
}
// p 是二进制为 1 的索引最大的位置的索引
// p 不动
for(int j = 0; j <= n; j ++){
f[now][p][0] += f[now ^ (1 << p - 1)][j][1];
f[now][p][1] += f[now ^ (1 << p - 1)][j][1];
}
// j 到 p,同时在 j 位置上放 k
for(int j = 1; j < p; j ++){
if((now & (1 << j - 1)) && belong[p][j] < belong[p][p]){
for(int k = 0; k <= n; k ++){
if(belong[j][k] < belong[j][j]){
f[now][j][1] += f[now ^ (1 << j - 1)][k][0];
}
}
}
if(now & (1 << j - 1)){
for(int k = 0; k <= n; k ++){
if(belong[j][k] < belong[j][j]){
f[now][j][0] += f[now ^ (1 << j - 1)][k][0];
}
}
}
}
}
}
}
int q = mread();
string s;
while(q --){
cin >> s;
int tmp = 0;
for(int i = 0; i < s.size(); i ++){
if(s[i] == 'H'){
tmp |= 1 << i;
}
}
int ans1 = 0, ans2 = 0;
for(int i = 0; i <= n; i ++){
ans1 += f[tmp][i][1];
ans2 += f[((1 << n) - 1) ^ tmp][i][1];
}
printf("%lld\n", ans1 * ans2);
}
return 0;
}