zoukankan      html  css  js  c++  java
  • Hdu 5396 Expression (区间Dp)

    题目链接:

      Hdu  5396 Expression

    题目描述:

      给出n个数字,n-1个符号。问不同的操作顺序得到的所有结果相加是多少?

    解题思路:

      n取值范围[1,100],肯定不能强行搜索。比赛的时候队友在这个题目上卡了好久,扎扎赛后决定把这个补了来拯救我快要卡哭了的队友。可以看出这个是明显的区间dp题目,dp[l][i]代表[l,r]这个区间内不同组合结果的总和。然后我们就要讨论怎么进行状态转移咯。由于'*', '-', '+'运算的性质,我们要分别对他们进行讨论。

      '*':有乘法的分配律可知,dp[l][r] = dp[l][k]*dp[k+1][r];

      '-'/'+':加减法就没有分配律咯,所以要分别在两边乘上一个阶乘,让两边的不同结果一一对应匹配。

      最后还要再乘上一个组合数,因为左右两边操作符在之前是有顺序的,但是两边合并以后两边的操作符在保证了自己的顺序后是可以混合的,也就是要在r - l  + 1个位置里挑出k-l个位置。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 const int maxn = 110;
     8 const int mod = 1000000007;
     9 typedef long long LL;
    10 LL dp[maxn][maxn], C[maxn], b[maxn];
    11 char op[maxn];
    12 //组合数用费马小定理取余
    13 LL Pow (LL x)
    14 {
    15     LL res = 1;
    16     LL n = mod - 2;
    17     while (n)
    18     {
    19         if (n % 2)
    20             res = (res * x) % mod;
    21         x = (x * x) % mod;
    22         n /= 2;
    23     }
    24     return res;
    25 }
    26 
    27 void init ()
    28 {//阶乘表
    29     C[0] = b[0] = 1;
    30     for (int i=1; i<maxn; i++)
    31     {
    32         C[i] = (C[i-1] * i) % mod;
    33         b[i] = Pow (C[i]);
    34     }
    35 }
    36 
    37 LL Sum (LL x, LL y, char p)
    38 {
    39     if (p == '+')
    40         return (x + y + mod) % mod;
    41     if (p == '-')
    42         return (x - y + mod) % mod;
    43     if (p == '*')
    44         return (x * y + mod) % mod;
    45 }
    46 
    47 int main ()
    48 {
    49     int n;
    50     init ();
    51     while (scanf ("%d", &n) != EOF)
    52     {
    53         memset (dp, 0, sizeof(dp));
    54         for (int i=0; i<n; i++)
    55         {
    56             scanf ("%lld", &dp[i][i]);
    57             dp[i][i] = (dp[i][i] + mod) % mod;
    58         }
    59         scanf ("%s", op+1);
    60         
    61         for (int j=0; j<n; j++)
    62         {//区间终点
    63             for (int i=j-1; i>=0; i--)//区间起点
    64                 for (int k=j; k>i; k--)
    65                 {//枚举区间内最后一个运算的符号
    66                     LL s1, s2;
    67                     
    68                     if (op[k] == '*')
    69                     {
    70                         s1 = dp[i][k-1];
    71                         s2 = dp[k][j];
    72                     }
    73                     else
    74                     {//加减法要乘两边符号的贡献
    75                         s1 = (dp[i][k-1] * C[j-k] + mod) % mod;
    76                         s2 = (dp[k][j] * C[k-i-1] + mod) % mod;
    77                     }
    78                     
    79                     s1 = (Sum(s1, s2, op[k]) * (C[j-i-1] * b[j-k] % mod * b[k-i-1] % mod) + mod) % mod;
    80                     //取余的时候一定要把组合数括起来,要不会死的很惨的,
    81                     dp[i][j] = (dp[i][j] + s1 + mod) % mod;
    82                 }
    83         }
    84         printf ("%lld
    ", dp[0][n-1]);
    85     }
    86     return 0;
    87 }
    本文为博主原创文章,未经博主允许不得转载。
  • 相关阅读:
    Go链接mongodb数据库
    pymongo插入报错
    Go Slice踩坑
    windows2003服务器系统日志:查看电脑远程登录记录
    解决Ubuntu中snap安装软件下载速度龟速问题。
    winsta0,session,desktop,winlogon,default
    关于idea运行时候控制台显示中文乱码问题
    从头开始学JavaScript (十三)——Date类型
    从头开始学JavaScript (十二)——Array类型
    从头开始学JavaScript (十一)——Object类型
  • 原文地址:https://www.cnblogs.com/alihenaixiao/p/4741939.html
Copyright © 2011-2022 走看看