博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AtCoder Regular Contest 095E - Symmetric Grid
阅读量:5090 次
发布时间:2019-06-13

本文共 1596 字,大约阅读时间需要 5 分钟。

$n \leq 12,m \leq 12$,$n$行$m$列小写字母,现可做无数次操作:交换两行;交换两列。问是否有可能把他变成中心对称的。

没有去想分组枚举的复杂度QAQ

行和列的操作顺序是随意的。假如说在一种最优方案中,操作是行行行……行列列列……列行行行……行列列列……列,那您把后面那堆行和前面那堆列换一下准保没问题:在一行的字母是不会变成不在同一行的,在一列的字母是不会变成不在同一列的,所以我瞄准最优方案,先把行放好位置,然后调列,一定能调好。可能比较抽象,反正他是对的,具体证明出门见其他大牛博客。

还有一件事,我枚举一种分配方案不需要枚举$n!$,很多都是重复的。怎么讲?先考虑这:我一种行的放法确定好,然后调列看合不合法。要合法的话,每个列都要和另一个列配上,这里的配上,就是一个取反后和另一个相等。如果m是奇数,那得有个列来当回文串放中间。这样子,假设现在放行的方案是$(p_1,p_2,...,p_n)$,如果咱变成$(p_2,p_1,...,p_n,p_{n-1})$,那跟前面那种是完全一样的(如果前面那种配上了这种也配上,如果前面那种配不上这种也配不上)。因此我只要把行打包成$n/2$对,然后每一对对称放,复杂度就会变成:多少啊,我每次从剩下的人里选一个考虑他配谁,选谁无所谓因为谁都要配,然后枚举他配谁,这样复杂度就是$(n-1)*(n-3)*...=(n-1)!!$。最大到10000多一点。行列都这么枚举加剪枝可以过。

诶您啥啊列何必像行那样枚举,每次枚举配上就配上了不改了,因此列枚举复杂度可以变成$n*m*m$,排序+二分可以变成$n*m*log_2m$。

1 //#include
2 #include
3 #include
4 //#include
5 //#include
6 //#include
7 #include
8 //#include
9 #include
10 using namespace std;11 12 int n,m;13 char mp[15][15];14 15 int a[15]; bool vis[15],ans=0;16 17 bool v2[15];18 bool check()19 {20 // for (int i=1;i<=n;i++) cout<
<<' ';cout<
n) {ans=check(); return;}51 if (vis[cur]) {dfs(cur+1,pos,odd); return;}52 53 for (int i=cur+1;i<=n;i++) if (!vis[i])54 {55 a[pos]=i; a[n-pos+1]=cur;56 vis[i]=1;57 dfs(cur+1,pos+1,odd);58 vis[i]=0;59 }60 if (odd)61 {62 a[(n>>1)+1]=cur;63 dfs(cur+1,pos,0);64 }65 }66 67 int main()68 {69 scanf("%d%d",&n,&m);70 for (int i=1;i<=n;i++) scanf("%s",mp[i]+1);71 dfs(1,1,n&1);72 puts(ans?"YES":"NO");73 return 0;74 }
View Code

 

转载于:https://www.cnblogs.com/Blue233333/p/8849571.html

你可能感兴趣的文章