• BZOJ 3990 [SDOI 2015] 排序 解题报告


    这个题哎呀。。。细节超级多。。。

    首先,我猜了一个结论。如果有一种排序方案是可行的,假设这个方案是 $S$ 。

    那么我们把 $S$ 给任意重新排列之后,也必然可以构造出一组合法方案来。

    于是我们就可以 $O(2^n)$ 枚举每个操作进不进行,再去判断,如果可行就 $ans$ += $|S|!$。

    然而怎么判断呢?

    我们按照操作种类从小到大操作。

    假设我们现在在决策第 $i$ 种操作并且保证之前之后不需要进行种类编号 $< i$ 的操作。

    那么我们只考虑那些位置在 $2^i+1$ 的位置的那些数。

    我们先找到所有的非法位置,满足下列条件之一就是非法位置,设当前位置为 $pos$:

    • 条件$1$:$A_{pos}$ 不能表示成 $a imes 2^i + 1$,其中 $a$ 为非负整数。
    • 条件$2$:$A_{pos + 2^{i-1}} e A_{pos} + 2^{i-1}$。

    满足以下三种情况之一即为无解:

    • 如果有三个或以上个非法位置,那么显然就无解了。
    • 如果没有非法位置,但是当前状态下必须要进行一次操作,那么无解。
    • 如果有非法位置,但是当前状态下必须不进行操作,那么无解。

    那么现在开始讨论:

    当没有非法位置的时候,直接递归求解。

    当只有一个非法位置的时候,交换 $A_{pos}$ 和 $A_{pos + 2^{i-1}}$,递归求解。

    这里本来应该交换一个区间的,然而有用的其实只有 $A_{pos}$ 和 $A_{pos + 2^{i-1}}$ 这两个数。

    因为其他的数字我们现在不会考虑,以后也更不用考虑了,反正保证是合法的,所以我们只交换这两个数。

    当有两个非法位置的时候,设两个非法位置为 $pos_1$ 和 $pos_2$

    我们把非法位置分两类:第一类是满足条件 $1$ 的,第二类是不满足条件 $1$ 但满足条件 $2$ 的。

    • $type(pos_1) = 2$ && $type(pos_2) = 2$:可以有两种可能合法的交换:交换 $A_{pos_1}$ 和 $A_{pos_2}$ 或者交换 $A_{pos_1 + 2^{i - 1}}$ 和 $A_{pos_2 + 2^{i - 1}}$。
    • $type(pos_1) = 2$ && $type(pos_2) = 1$:只有一种可能合法的交换:交换 $A_{pos_1 + 2^{i - 1}}$ 和 $A_{pos_2}$。
    • $type(pos_1) = 1$ && $type(pos_2) = 2$:只有一种可能合法的交换:交换 $A_{pos_1}$ 和 $A_{pos_2 + 2^{i - 1}}$。
    • $type(pos_1) = 1$ && $type(pos_2) = 1$:无解。

    然后递归求解即可。注意每当交换完之后要判断原来的非法位置是否变合法了,如果还是非法的那么就直接判掉。

    判断每个状态的复杂度:

    $$sum_{i=1}^{n}2^i imesfrac{2^n}{2^i} = sum_{i=1}^{n}2^n = n imes 2^n$$

    于是整个问题的复杂度就是:$O(n2^{2n})$ 的了。

    然而常数很小很小,应该很难构造一组卡到上界的数据,所以跑得还是比较快的。。。

      1  
      2 #include <cmath>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <iostream>
      6 #include <algorithm>
      7 using namespace std;
      8 typedef long long LL;
      9 #define N 12 + 5
     10 #define SIZE 1 << 12 | 5
     11  
     12 int n;
     13 LL ans;
     14 LL Fac[N];
     15 int A[SIZE], Cnt[SIZE];
     16  
     17 inline bool dfs(int state, int len)
     18 {
     19     if (len >> (n + 1)) return 1;
     20     int cnt = 0, pos_1, pos_2;
     21     for (int i = 0; i < (1 << n); i += len)
     22     {
     23         int _i = i + (len >> 1);
     24         if ((A[i] & (len - 1)) || A[_i] != A[i] + (len >> 1))
     25         {
     26             cnt ++;
     27             if (cnt == 1) pos_1 = i;
     28             else if (cnt == 2) pos_2 = i;
     29             else return 0;
     30         }
     31     }
     32     if ((state & 1) == 0 && cnt) return 0;
     33     if ((state & 1) && !cnt) return 0;
     34     if (!cnt) return dfs(state >> 1, len << 1);
     35     if (cnt == 1)
     36     {
     37         swap(A[pos_1], A[pos_1 + (len >> 1)]);
     38         bool ok = dfs(state >> 1, len << 1);
     39         swap(A[pos_1], A[pos_1 + (len >> 1)]);
     40         return ok;
     41     }
     42     if (cnt == 2)
     43     {
     44         bool ok = 1;
     45         if ((A[pos_1] & (len - 1)) && (A[pos_2] & (len - 1))) return 0;
     46         else if (A[pos_1] & (len - 1))
     47         {
     48             swap(A[pos_1], A[pos_2 + (len >> 1)]);
     49             if (A[pos_1] + (len >> 1) != A[pos_1 + (len >> 1)]) ok = 0;
     50             if (A[pos_2] + (len >> 1) != A[pos_2 + (len >> 1)]) ok = 0;
     51             if (ok) ok = dfs(state >> 1, len << 1);
     52             swap(A[pos_1], A[pos_2 + (len >> 1)]);
     53             return ok;
     54         }
     55         else if (A[pos_2] & (len - 1))
     56         {
     57             swap(A[pos_2], A[pos_1 + (len >> 1)]);
     58             if (A[pos_1] + (len >> 1) != A[pos_1 + (len >> 1)]) ok = 0;
     59             if (A[pos_2] + (len >> 1) != A[pos_2 + (len >> 1)]) ok = 0;
     60             if (ok) ok = dfs(state >> 1, len << 1);
     61             swap(A[pos_2], A[pos_1 + (len >> 1)]);
     62             return ok;
     63         }
     64         else
     65         {
     66             swap(A[pos_1], A[pos_2]);
     67             if (A[pos_1] + (len >> 1) != A[pos_1 + (len >> 1)]) ok = 0;
     68             if (A[pos_2] + (len >> 1) != A[pos_2 + (len >> 1)]) ok = 0;
     69             if (ok) ok = dfs(state >> 1, len << 1);
     70             swap(A[pos_1], A[pos_2]);
     71             if (ok) return 1;
     72              
     73             ok = 1;
     74             swap(A[pos_1 + (len >> 1)], A[pos_2 + (len >> 1)]);
     75             if (A[pos_1] + (len >> 1) != A[pos_1 + (len >> 1)]) ok = 0;
     76             if (A[pos_2] + (len >> 1) != A[pos_2 + (len >> 1)]) ok = 0;
     77             if (ok) ok = dfs(state >> 1, len << 1);
     78             swap(A[pos_1 + (len >> 1)], A[pos_2 + (len >> 1)]);
     79             return ok;
     80         }
     81     }
     82 }
     83  
     84 int main()
     85 {
     86     #ifndef ONLINE_JUDGE
     87         freopen("3990.in", "r", stdin);
     88         freopen("3990.out", "w", stdout);
     89     #endif
     90      
     91     scanf("%d", &n);
     92     Fac[0] = 1;
     93     for (int i = 1; i <= n; i ++)
     94         Fac[i] = Fac[i - 1] * i;
     95     for (int i = 1; i <= (1 << n); i ++)
     96     {
     97         scanf("%d", A + i - 1);
     98         A[i - 1] --;
     99         Cnt[i] = Cnt[i - (i & -i)] + 1;
    100     }
    101     for (int s = 0; s < (1 << n); s ++)
    102         if (dfs(s, 2)) ans += Fac[Cnt[s]];
    103     printf("%lld
    ", ans);
    104      
    105     #ifndef ONLINE_JUDGE
    106         fclose(stdin);
    107         fclose(stdout);
    108     #endif
    109     return 0;
    110 }
    3990_Gromah
  • 相关阅读:
    java8特性 Optional 工具类
    SpringBoot 配置支付宝接口
    Redis宕机 快速恢复
    flowable流程引擎通过模型ID部署流程
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
    Mybatis 动态执行SQL语句
    idea 访问 jsp 404问题
    变量名的命名
    CSS设计 Search窗口
    jQuery实现Ajax功能示例
  • 原文地址:https://www.cnblogs.com/gromah/p/4433402.html
Copyright © 2020-2023  润新知