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代码
  • 相关阅读:
    redis发布订阅
    redis学习笔记(面试题)
    redis安全 (error) NOAUTH Authentication required
    HDU3001 Travelling —— 状压DP(三进制)
    POJ3616 Milking Time —— DP
    POJ3186 Treats for the Cows —— DP
    HDU1074 Doing Homework —— 状压DP
    POJ1661 Help Jimmy —— DP
    HDU1260 Tickets —— DP
    HDU1176 免费馅饼 —— DP
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10673162.html
Copyright © 2011-2022 走看看