zoukankan      html  css  js  c++  java
  • LOJ#2304 泳池

    题意:有一个1001 * n的矩形,每个位置有q的概率为1。求紧贴下边界的最大的全1子矩形面积恰为k的概率。n <= 1e9,k <= 1000。

    解:只需考虑每一列最下面一个0的位置。

    首先有个n = 1的部分分,答案显然就是qk(1-q)。

    中间还有些部分分,什么打表啊笛卡尔树上DP啊...感觉有毒。

    接下来就是一个nk的DP,直接获得70分...感觉有毒。

    首先发现这个恰好为k不好处理,就考虑计算<= k和<= k - 1,然后相减。注意因为面积全是整数而我们不是求期望,所以不会有非整数的出现。

    考虑到下边界一定被若干个0分隔开,且每两个相邻0之间距离不大于k。于是我们按照0来DP。设fi表示1001 * i的矩形符合条件的概率。那么每次枚举这一段下边界的最后一个0在j位置,那么概率就是fj-1 * (1 - q) * (长为i-j的一段最下面全是1,符合条件的概率)。

    考虑怎么求最后那个东西。

    发现把最下面一行去掉之后好像有点像一个子问题?然而好像不行...实际上是一种类似最值分治的做法。

    考虑这些列中最低的一列在哪(枚举得到),然后左右两边就是一个真实子问题,而中间这一列就是n = 1的部分分。但是还是不知道最低一列到底有多低...发现k只有1000,所以就可以枚举?

    然而正解是多加一维状态表示高度。设gi,j表示1001 * i的矩形,最下面j * i的矩形全是1,且满足条件的概率。设j + 1行第一个0在p位置,那么gi,j += gp-1,j+1 * gi-p,j * qj * (1-q)。

    边界条件就是g0,x = 1。

    这东西难调死了......注意fn其实等于gn,0

     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 = 1010, MO = 998244353;
    17 
    18 int n, K, q, g[N][N], f[N], pw[N];
    19 
    20 inline int qpow(int a, int b) {
    21     int ans = 1;
    22     while(b) {
    23         if(b & 1) ans = 1ll * ans * a % MO;
    24         a = 1ll * a * a % MO;
    25         b = b >> 1;
    26     }
    27     return ans;
    28 }
    29 
    30 inline int cal(int k) {
    31     if(k < 0) return 0;
    32     if(k == 0) return qpow(1 - q + MO, n);
    33     memset(f, 0, sizeof(f));
    34     memset(g, 0, sizeof(g));
    35 
    36     for(int i = 0; i <= k + 1; i++) {
    37         g[0][i] = 1;
    38     }
    39 
    40     for(int i = 1; i <= k; i++) {
    41         for(int j = k / i; j >= 0; j--) {
    42             /// g[i][j]
    43             g[i][j] = g[i][j + 1];
    44             for(int p = 1; p <= i; p++) {
    45                 (g[i][j] += 1ll * g[p - 1][j + 1] * g[i - p][j] % MO * pw[j] % MO * (1 - q + MO) % MO) %= MO;
    46             }
    47             //printf("g %d %d = %d 
    ", i, j, g[i][j]);
    48         }
    49     }
    50 
    51     //puts("");
    52 
    53     /// cal f
    54     f[0] = 1;
    55     for(int i = 1; i <= n; i++) {
    56         /// f[i]
    57         if(i <= k) f[i] = g[i][1];
    58         for(int j = std::max(1, i - k); j <= i; j++) {
    59             (f[i] += 1ll * f[j - 1] * (1 - q + MO) % MO * g[i - j][1] % MO) %= MO;
    60         }
    61         //printf("f %d = %d 
    ", i, f[i]);
    62     }
    63 
    64     //printf("
    
    ");
    65 
    66     return f[n];
    67 }
    68 
    69 /*
    70 2 2 1 2
    71 */
    72 
    73 int main() {
    74     int x, y;
    75     scanf("%d%d%d%d", &n, &K, &x, &y);
    76     q = 1ll * x * qpow(y, MO - 2) % MO;
    77     //printf("q = %d 
    ", q);
    78     pw[0] = 1;
    79     for(int i = 1; i <= K; i++) {
    80         pw[i] = 1ll * pw[i - 1] * q % MO;
    81     }
    82 
    83     if(n == 1) {
    84         int ans = 1ll * qpow(q, K) * (1 - q + MO) % MO;
    85         printf("%d
    ", ans);
    86         return 0;
    87     }
    88 
    89     int ans = (cal(K) - cal(K - 1) + MO) % MO;
    90     printf("%d
    ", ans);
    91 
    92     return 0;
    93 }
    70分代码

    于是我们来个矩阵快速幂优化,获得了90分的好成绩!

      1 #include <bits/stdc++.h>
      2 
      3 typedef long long LL;
      4 const int N = 1010, MO = 998244353;
      5 
      6 int n, K, q, g[N][N], f[N], pw[N];
      7 int A[110][110], ANS[110][110], C[110][110];
      8 
      9 inline int qpow(int a, int b) {
     10     int ans = 1;
     11     while(b) {
     12         if(b & 1) ans = 1ll * ans * a % MO;
     13         a = 1ll * a * a % MO;
     14         b = b >> 1;
     15     }
     16     return ans;
     17 }
     18 
     19 inline void mulself(int k) {
     20     memset(C, 0, sizeof(C));
     21     for(int p = 0; p <= k; p++) {
     22         for(int j = 0; j <= k; j++) {
     23             for(int i = 0; i <= k; i++) {
     24                 (C[i][j] += 1ll * A[i][p] * A[p][j] % MO) %= MO;
     25             }
     26         }
     27     }
     28     memcpy(A, C, sizeof(A));
     29     return;
     30 }
     31 
     32 inline void mul(int k) {
     33     memset(C, 0, sizeof(C));
     34     for(int p = 0; p <= k; p++) {
     35         for(int j = 0; j <= k; j++) {
     36             for(int i = 0; i <= k; i++) {
     37                 (C[i][j] += 1ll * ANS[i][p] * A[p][j] % MO) %= MO;
     38             }
     39         }
     40     }
     41     memcpy(ANS, C, sizeof(C));
     42     return;
     43 }
     44 
     45 inline int cal(int k) {
     46     if(k < 0) return 0;
     47     if(k == 0) return qpow(1 - q + MO, n);
     48     memset(f, 0, sizeof(f));
     49     memset(g, 0, sizeof(g));
     50 
     51     for(int i = 0; i <= k + 1; i++) {
     52         g[0][i] = 1;
     53     }
     54 
     55     for(int i = 1; i <= k; i++) {
     56         for(int j = k / i; j >= 0; j--) {
     57             /// g[i][j]
     58             g[i][j] = g[i][j + 1];
     59             for(int p = 1; p <= i; p++) {
     60                 (g[i][j] += 1ll * g[p - 1][j + 1] * g[i - p][j] % MO * pw[j] % MO * (1 - q + MO) % MO) %= MO;
     61             }
     62             //printf("g %d %d = %d 
    ", i, j, g[i][j]);
     63         }
     64     }
     65 
     66     //puts("");
     67 
     68     /// cal f
     69     if(n <= 1000) {
     70         f[0] = 1;
     71         for(int i = 1; i <= n; i++) {
     72             /// f[i]
     73             if(i <= k) f[i] = g[i][1];
     74             for(int j = std::max(1, i - k); j <= i; j++) {
     75                 (f[i] += 1ll * f[j - 1] * (1 - q + MO) % MO * g[i - j][1] % MO) %= MO;
     76             }
     77             //printf("f %d = %d 
    ", i, f[i]);
     78         }
     79         return f[n];
     80     }
     81     else {
     82         memset(ANS, 0, sizeof(ANS));
     83         for(int i = 0; i <= k; i++) {
     84             ANS[i][i] = 1;
     85         }
     86         memset(A, 0, sizeof(A));
     87         for(int i = 0; i < k; i++) {
     88             A[i + 1][i] = 1;
     89         }
     90         for(int i = 0; i <= k; i++) {
     91             A[i][k] = 1ll * g[k - i][1] * (1 - q + MO) % MO;
     92         }
     93         int b = n - k;
     94         while(b) {
     95             if(b & 1) {
     96                 mul(k);
     97             }
     98             mulself(k);
     99             b = b >> 1;
    100         }
    101         /// mul g ans
    102         int ans = 0;
    103         for(int i = 0; i <= k; i++) {
    104             (ans += 1ll * g[i][0] * ANS[i][k] % MO) %= MO;
    105         }
    106         return ans;
    107     }
    108 }
    109 
    110 /*
    111 2 2 1 2
    112 */
    113 
    114 int main() {
    115     int x, y;
    116     scanf("%d%d%d%d", &n, &K, &x, &y);
    117     q = 1ll * x * qpow(y, MO - 2) % MO;
    118     //printf("q = %d 
    ", q);
    119     pw[0] = 1;
    120     for(int i = 1; i <= K; i++) {
    121         pw[i] = 1ll * pw[i - 1] * q % MO;
    122     }
    123 
    124     if(n == 1) {
    125         int ans = 1ll * qpow(q, K) * (1 - q + MO) % MO;
    126         printf("%d
    ", ans);
    127         return 0;
    128     }
    129 
    130     int ans = (cal(K) - cal(K - 1) + MO) % MO;
    131     printf("%d
    ", ans);
    132 
    133     return 0;
    134 }
    90分代码

    弃疗了弃疗了...

  • 相关阅读:
    背水一战 Windows 10 (61)
    背水一战 Windows 10 (60)
    背水一战 Windows 10 (59)
    背水一战 Windows 10 (58)
    背水一战 Windows 10 (57)
    背水一战 Windows 10 (56)
    背水一战 Windows 10 (55)
    背水一战 Windows 10 (54)
    背水一战 Windows 10 (53)
    背水一战 Windows 10 (52)
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10748677.html
Copyright © 2011-2022 走看看