首页 > 技术文章 > BZOJ 3990 [SDOI 2015] 排序 解题报告

gromah 2015-04-16 21:50 原文

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

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

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

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

然而怎么判断呢?

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

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

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

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

  • 条件$1$:$A_{pos}$ 不能表示成 $a\times 2^i + 1$,其中 $a$ 为非负整数。
  • 条件$2$:$A_{pos + 2^{i-1}} \ne 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\times\frac{2^n}{2^i} = \sum_{i=1}^{n}2^n = n\times 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\n", ans);
104      
105     #ifndef ONLINE_JUDGE
106         fclose(stdin);
107         fclose(stdout);
108     #endif
109     return 0;
110 }
3990_Gromah

 

推荐阅读