• 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分代码

    弃疗了弃疗了...

  • 相关阅读:
    计算 时间戳 时间差
    Convert.ToInt32(string '000000003') 变成了 3
    mvc 二级域名 重定向
    访问微信的统一下单接口经常超时 操作超时
    EF 批量更新删除(linq篇)
    java提供了native2ascii工具
    局域网内Tomcat服务器没法访问
    程序实现发送邮件
    InputStream和OutputStream与String之间的转换
    开发中/listfile.jsp(11,31) quote symbol expected 这个错误
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10748677.html
Copyright © 2020-2023  润新知