[??记录]AT4113 [ARC095C] Symmetric Grid

command_block

2021-05-04 19:32:23

Personal

**题意** : 给定一个包含小写字母的矩阵,每次可以整体交换两行或两列,求是否可以将其变成一个中心对称的矩阵。 $n,m\leq 12$ ,时限$\texttt{2s}$。 ------------ 先枚举列的置换,然后考虑如何判定是存在交换行的方案使得合法。 对于给定的 $n$ 个字符串,需要两两配对(若总数为奇数,剩下的必须是回文串),满足 $S_1={\rm reverse}(S_2)$。 字符串哈希一手,可以用 `long long` 装下,于是容易 $O\big(n(m+n)\big)$ 判定是否匹配。 若枚举所有的置换,复杂度为 $O(n!nm)$ ,无法通过。 实际上,我们只关心列翻转后的两两对应,故只需要枚举所有的匹配。而匹配的数目是 $11\times 9\times 7\times 5\times 3\times 1=10395$ 的,于是可以通过。 ```cpp #include<algorithm> #include<cstdio> #define ll long long using namespace std; int n,m,p[15]; char s[15][15]; ll s1[15],s2[15]; bool vis[15],ans; void dfs(int cnt,bool fl) { if (cnt==m){ for (int i=1;i<=n;i++){ s2[i]=0; for (int j=1;j<=m;j++) s2[i]=s2[i]*26+s[i][p[j]]-'a'; } for (int i=1;i<=n;i++)vis[i]=0; int tmp=0; for (int i=1;i<=n;i++)if (!vis[i]){ bool fl=0; for (int j=i+1;j<=n;j++) if (!vis[j]&&s1[i]==s2[j]) {vis[j]=fl=1;break;} if (!fl){ if (s1[i]!=s2[i])return; tmp++; } }ans|=(tmp<=1); return ; } int i=1;while(p[i])i++; if (fl){p[i]=i;dfs(cnt+1,0);p[i]=0;} for (int j=i+1;j<=m;j++)if (!p[j]){ p[i]=j;p[j]=i; dfs(cnt+2,fl); p[i]=p[j]=0; } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++){ scanf("%s",s[i]+1); for (int j=1;j<=m;j++) s1[i]=s1[i]*26+s[i][j]-'a'; } dfs(0,m&1); puts(ans ? "YES" : "NO"); return 0; } ```