zoukankan      html  css  js  c++  java
  • 洛谷P4769 冒泡排序

    n <= 60w,∑n <= 200w,1s。

    解:首先有个全排列 + 树状数组的暴力。

    然后有个没有任何规律的状压...首先我想的是按照大小顺序来放数,可以分为确定绝对位置和相对位置两种,但是都不好处理字典序。

    然后换个思路一位一位的考虑放哪个数。用一维来记录|i - pi| - 逆序对数 * 2,还有一维记录是否紧贴下限,一个二进制数记录之前填了哪些数。

    当前填到哪一位可以通过二进制中1的个数统计出来。这样就是一个n32n的做法,可以过n <= 14的点,得到24分。

     1 /**
     2  * There is no end though there is a start in space. ---Infinity.
     3  * It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
     4  * Only the person who was wisdom can read the most foolish one from the history.
     5  * The fish that lives in the sea doesn't know the world in the land.
     6  * It also ruins and goes if they have wisdom.
     7  * It is funnier that man exceeds the speed of light than fish start living in the land.
     8  * It can be said that this is an final ultimatum from the god to the people who can fight.
     9  *
    10  * Steins;Gate
    11  */
    12 
    13 #include <bits/stdc++.h>
    14 
    15 const int N = 600010, MO = 998244353;
    16 
    17 int p[N], n;
    18 
    19 inline void Add(int &a, const int &b) {
    20     a += b;
    21     while(a >= MO) a -= MO;
    22     while(a < 0) a += MO;
    23     return;
    24 }
    25 
    26 inline void out(int x) {
    27     for(int i = 0; i < n; i++) {
    28         printf("%d", (x >> i) & 1);
    29     }
    30     return;
    31 }
    32 
    33 namespace Sta {
    34     const int DT = 500, M = 33000;
    35     int f[DT * 2][M][2], cnt[M], pw[M];
    36     inline void prework() {
    37         for(int i = 1; i < M; i++) {
    38             cnt[i] = 1 + cnt[i - (i & (-i))];
    39         }
    40         for(int i = 2; i < M; i++) {
    41             pw[i] = pw[i >> 1] + 1;
    42         }
    43         return;
    44     }
    45     inline void solve() {
    46         memset(f, 0, sizeof(f));
    47         f[DT][0][0] = 1;
    48         /// DP
    49         int lm = (1 << n) - 1, lm2 = n * (n - 1) / 2; /// lm : 11111111111
    50         for(int s = 0; s < lm; s++) {
    51             for(int i = -lm2; i <= lm2; i++) {
    52                 /// f[i + DT][s][0/1]
    53                 if(!f[i + DT][s][0] && !f[i + DT][s][1]) continue;
    54                 //printf("f %d ", i); out(s); printf(" 0 = %d  1 = %d 
    ", f[i + DT][s][0], f[i + DT][s][1]);
    55                 int t = lm ^ s;
    56                 while(t) {
    57                     int j = pw[t & (-t)] + 1, temp = i + std::abs(cnt[s] + 1 - j) - cnt[s >> (j - 1)] * 2 + DT, t2 = s | (1 << (j - 1));
    58                     /// f[i + DT][s][1] -> f[std::abs(cnt[s] + 1 - j) - cnt[s >> (j - 1)] + DT][s | (1 << (j - 1))][1]
    59                     Add(f[temp][t2][1], f[i + DT][s][1]);
    60                     //printf("1 > %d ", temp - DT); out(t2); printf(" 1 = %d
    ", f[temp][t2][1]);
    61                     if(j > p[cnt[s] + 1]) {
    62                         Add(f[temp][t2][1], f[i + DT][s][0]);
    63                         //printf("0 > %d ", temp - DT); out(t2); printf(" 1 = %d
    ", f[temp][t2][1]);
    64                     }
    65                     else if(j == p[cnt[s] + 1]) {
    66                         Add(f[temp][t2][0], f[i + DT][s][0]);
    67                         //printf("0 > %d ", temp - DT); out(t2); printf(" 0 = %d
    ", f[temp][t2][0]);
    68                     }
    69                     t ^= 1 << (j - 1);
    70                 }
    71             }
    72         }
    73 
    74         printf("%d
    ", f[DT][lm][1]);
    75         return;
    76     }
    77 }
    78 
    79 int main() {
    80     //printf("%d 
    ", (sizeof(Sta::f)) / 1048576);
    81     int T;
    82     scanf("%d", &T);
    83     Sta::prework();
    84     while(T--) {
    85         scanf("%d", &n);
    86         for(int i = 1; i <= n; i++) {
    87             scanf("%d", &p[i]);
    88         }
    89         Sta::solve();
    90     }
    91     return 0;
    92 }
    24分状压

     然后我们必须开始找规律了......这里我是完全没思路(太过SB)

    冷静分析一波发现,一个合法的排列等价于一个不存在长度为三的下降子序列的排列。

    因为如果存在长度为3的下降子序列,那么中间那个元素一定有一次移动不是如它所想的。而不存在的话,我们就可以归纳,冒泡排序每一步都会减少一对逆序对,下降子序列一定不会变长。(全是口胡,意会就行了)

    然后有一个44分的状压DP出来了,我没写...

    80分n2DP,先考虑怎么求答案。枚举哪个位置开始自由,如果在i开始自由的话就要知道后面有多少种填法。所以我们需要一个从当前状态到终态的状态,而不是从初态到当前。

    (看题解)发现如果前缀最大值为j,那么当前要么填比j小的最小的,要么填比j大的。因为如果填了比j小的又不是最小的,就会有一个长为3的下降子序列。

    然后设fi,j表示还剩i位要填,能填的数中比max(1~i)大的有j个,填满的方案数。

    于是有f[i][j] = ∑f[i - 1][k] = f[i][j - 1] + f[i - 1][j]

    于是枚举在哪自由,然后把对应的j求出来。每个位置要加上fn-i,0~j-1

    注意有两个地方要break,一个是后面没有比max(1~i)大的数了,还有就是当前填了长为3的下降子序列了。

    100分:发现f这个东西其实就是格路径方案数......特别注意i < j的时候为0,所以有一条线不能跨过......

    组合数学一波,就能O(1)计算f了。然后发现这个东西fn-i,0~j-1不就是fn-i+1,j-1吗?然后就完事了,nlogn。

      1 /**
      2  * There is no end though there is a start in space. ---Infinity.
      3  * It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
      4  * Only the person who was wisdom can read the most foolish one from the history.
      5  * The fish that lives in the sea doesn't know the world in the land.
      6  * It also ruins and goes if they have wisdom.
      7  * It is funnier that man exceeds the speed of light than fish start living in the land.
      8  * It can be said that this is an final ultimatum from the god to the people who can fight.
      9  *
     10  * Steins;Gate
     11  */
     12 
     13 #include <bits/stdc++.h>
     14 
     15 typedef long long LL;
     16 const int N = 600010, MO = 998244353;
     17 
     18 int p[N], n;
     19 int fac[N << 1], inv[N << 1], invn[N << 1];
     20 
     21 inline LL C(int n, int m) {
     22     if(n < 0 || m < 0 || n < m) return 0;
     23     return 1ll * fac[n] * invn[m] % MO * invn[n - m] % MO;
     24 }
     25 
     26 inline void Add(int &a, const int &b) {
     27     a += b;
     28     while(a >= MO) a -= MO;
     29     while(a < 0) a += MO;
     30     return;
     31 }
     32 
     33 inline void out(int x) {
     34     for(int i = 0; i < n; i++) {
     35         printf("%d", (x >> i) & 1);
     36     }
     37     return;
     38 }
     39 
     40 namespace Sta {
     41     const int DT = 500, M = 33000;
     42     int f[DT * 2][M][2], cnt[M], pw[M];
     43     inline void prework() {
     44         for(int i = 1; i < M; i++) {
     45             cnt[i] = 1 + cnt[i - (i & (-i))];
     46         }
     47         for(int i = 2; i < M; i++) {
     48             pw[i] = pw[i >> 1] + 1;
     49         }
     50         return;
     51     }
     52     inline void solve() {
     53         memset(f, 0, sizeof(f));
     54         f[DT][0][0] = 1;
     55         /// DP
     56         int lm = (1 << n) - 1, lm2 = n * (n - 1) / 2; /// lm : 11111111111
     57         for(int s = 0; s < lm; s++) {
     58             for(int i = -lm2; i <= lm2; i++) {
     59                 /// f[i + DT][s][0/1]
     60                 if(!f[i + DT][s][0] && !f[i + DT][s][1]) continue;
     61                 //printf("f %d ", i); out(s); printf(" 0 = %d  1 = %d 
    ", f[i + DT][s][0], f[i + DT][s][1]);
     62                 int t = lm ^ s;
     63                 while(t) {
     64                     int j = pw[t & (-t)] + 1, temp = i + std::abs(cnt[s] + 1 - j) - cnt[s >> (j - 1)] * 2 + DT, t2 = s | (1 << (j - 1));
     65                     /// f[i + DT][s][1] -> f[std::abs(cnt[s] + 1 - j) - cnt[s >> (j - 1)] + DT][s | (1 << (j - 1))][1]
     66                     Add(f[temp][t2][1], f[i + DT][s][1]);
     67                     //printf("1 > %d ", temp - DT); out(t2); printf(" 1 = %d
    ", f[temp][t2][1]);
     68                     if(j > p[cnt[s] + 1]) {
     69                         Add(f[temp][t2][1], f[i + DT][s][0]);
     70                         //printf("0 > %d ", temp - DT); out(t2); printf(" 1 = %d
    ", f[temp][t2][1]);
     71                     }
     72                     else if(j == p[cnt[s] + 1]) {
     73                         Add(f[temp][t2][0], f[i + DT][s][0]);
     74                         //printf("0 > %d ", temp - DT); out(t2); printf(" 0 = %d
    ", f[temp][t2][0]);
     75                     }
     76                     t ^= 1 << (j - 1);
     77                 }
     78             }
     79         }
     80 
     81         printf("%d
    ", f[DT][lm][1]);
     82         return;
     83     }
     84 }
     85 
     86 namespace Stable {
     87 
     88     int ta[N];
     89 
     90     inline void add(int i) {
     91         for(; i <= n; i += i & (-i)) ta[i]++;
     92         return;
     93     }
     94     inline int ask(int i) {
     95         int ans = 0;
     96         for(; i; i -= i & (-i)) {
     97             ans += ta[i];
     98         }
     99         return ans;
    100     }
    101     inline void clear() {
    102         memset(ta + 1, 0, n * sizeof(int));
    103         return;
    104     }
    105 
    106     inline bool check() {
    107         int ans = 0, cnt = 0;
    108         for(int i = n; i >= 1; i--) {
    109             cnt += std::abs(i - p[i]);
    110             ans += ask(p[i] - 1);
    111             add(p[i]);
    112         }
    113         clear();
    114         return cnt == ans * 2;
    115     }
    116 
    117     inline int cal() {
    118         int ans = 0;
    119         for(int i = 1; i <= n; i++) {
    120             if(p[i] < p[i - 1]) ans++;
    121         }
    122         return ans + 1;
    123     }
    124 
    125     inline void work() {
    126         for(n = 1; n <= 10; n++) {
    127             for(int i = 1; i <= n; i++) p[i] = i;
    128             do {
    129                 if(check()) {
    130                     for(int i = 1; i <= n; i++) {
    131                         printf("%d ", p[i]);
    132                     }
    133                 }
    134                 else {
    135                     printf("ERR : ");
    136                     for(int i = 1; i <= n; i++) {
    137                         printf("%d ", p[i]);
    138                     }
    139                 }
    140                 printf("  cal = %d 
    ", cal());
    141             } while(std::next_permutation(p + 1, p + n + 1));
    142             getchar();
    143         }
    144         return;
    145     }
    146 }
    147 
    148 namespace DP {
    149     const int M = 1010;
    150     int f[M][M], ta[N];
    151     inline void add(int i) {
    152         for(; i <= n; i += i & (-i)) ta[i]++;
    153         return;
    154     }
    155     inline int ask(int i) {
    156         int ans = 0;
    157         for(; i; i -= i & (-i)) {
    158             ans += ta[i];
    159         }
    160         return ans;
    161     }
    162     inline int getSum(int l, int r) {
    163         return ask(r) - ask(l - 1);
    164     }
    165     inline int F(int i, int j) {
    166         if(i < j) return 0;
    167         return (C(i + j - 1, j) - C(i + j - 1, i + 1) + MO) % MO;
    168     }
    169     inline void solve() {
    170         /*memset(f, 0, sizeof(f));
    171         f[0][0] = 1;
    172         for(int i = 1; i <= n; i++) {
    173             for(int j = 0; j <= i; j++) {
    174                 f[i][j] = (f[i - 1][j] + f[i][j - 1]) % MO;
    175             }
    176         }*/
    177 
    178         /*for(int j = n; j >= 0; j--) {
    179             for(int i = 0; i <= n; i++) {
    180                 printf("%3d ", f[i][j]);
    181             }
    182             puts("");
    183         }*/
    184 
    185         int ans = 0, pre = 0;
    186         for(int i = 1; i < n; i++) {
    187             /// [1, i - 1] ==   i >
    188             pre = std::max(pre, p[i]);
    189             int k = n - pre - getSum(pre + 1, n);
    190             //printf("i = %d k = %d 
    ", i, k);
    191             if(!k) break;
    192             /*for(int j = 0; j < k; j++) {
    193                 Add(ans, F(n - i, j));
    194                 //printf("add f %d %d 
    ", n - i, j);
    195             }*/
    196             Add(ans, F(n - i + 1, k - 1));
    197             add(p[i]);
    198             if(p[i] < pre && ask(p[i]) != p[i]) break;
    199         }
    200         printf("%d
    ", ans);
    201         memset(ta + 1, 0, n * sizeof(int));
    202         return;
    203     }
    204 }
    205 
    206 int main() {
    207     //printf("%d 
    ", (sizeof(Sta::f)) / 1048576);
    208     //Stable::work();
    209     fac[0] = inv[0] = invn[0] = 1;
    210     fac[1] = inv[1] = invn[1] = 1;
    211     for(int i = 2; i < N * 2; i++) {
    212         fac[i] = 1ll * fac[i - 1] * i % MO;
    213         inv[i] = 1ll * inv[MO % i] * (MO - MO / i) % MO;
    214         invn[i] = 1ll * invn[i - 1] * inv[i] % MO;
    215     }
    216     int T;
    217     scanf("%d", &T);
    218     //Sta::prework();
    219     while(T--) {
    220         scanf("%d", &n);
    221         for(int i = 1; i <= n; i++) {
    222             scanf("%d", &p[i]);
    223         }
    224         DP::solve();
    225     }
    226     return 0;
    227 }
    AC代码
  • 相关阅读:
    《构建之法》读书笔记六
    《构建之法》读书笔记五
    《构建之法》读书笔记四
    《构建之法》读书笔记三
    《构建之法》读书笔记二
    《构建之法》读书笔记一
    开发mis系统需要的技术
    java异常处理
    多态
    动手动脑6
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10673162.html
Copyright © 2011-2022 走看看