HDU--5396(区间dp+排列组合)

做这道题的时候,想到会不会是dp,然后发现dp可做,但是一直被自己坑到死。

枚举最后合并的那个位置,然后对于加减号的,分成的前后两个部分都有不同的组合方法,

(a1+a2........) +  (b1,b2.............)         对于每个a,被加b的个数的阶乘次 ,对于每个b,被加a的个数的阶乘次

减法同理

乘法特殊一点

(a1+a2........) *  (b1,b2.............)  乘法分配率,直接将两部分的总和相乘即可

想到这些还远远没有结束,因为最后两个区间合并的时候,还牵扯到一个顺序问题,一开始还好傻好天真直接乘了2,结果呵呵哒了。

如果共有N个符号,i左边x个,右边y个,那么因为枚举了i这个最后合并的位置,所以最后一个进行运算的符号是确定的,处理完左右的得出的数字分别被加过多少次之后,还要处理这个得出的总数因为合并的顺序不同被多加过多少次,就是C(N-1,x) 其中选出的这x个位置中保持i左边符号的相对顺序不变,因为之前变过顺序的那个前面已经处理过了。。自己理解这里一开始有点问题,总是混,特别怕dp计数,尤其跟排列组合混起来,感觉脑子差一截……

#pragma comment(linker,"/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <map>
#include <utility>
#include <algorithm>
#include <iostream>
#define mem(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f
using namespace std;
int dx[]= {-1,0,1,0};///n e s w
int dy[]= {0,1,0,-1};
typedef long long ll;
typedef pair<int,int> pii;
const int maxd=200+5;
///==============================
const int mod=1000000007;
ll dp[maxd][maxd],a[maxd],fac[maxd],c[maxd][maxd];
int n;
char str[maxd];

void init()
{
    fac[0]=1;
    for(int i=1; i<maxd; i++)
        fac[i]=fac[i-1]*i%mod;

    mem(c,0);
    for(int i=0; i<maxd; i++)
    {
        c[i][0]=1;
        for(int j=1; j<=i; j++)
            (c[i][j]=c[i-1][j-1]+c[i-1][j])%=mod;
    }
}

ll dfs(int l,int r)
{
    ll &res=dp[l][r];
    if(res!=mod) return res;

    if(l==r)
        return res=a[l];

    res=0;
    for(int i=l; i<r ; i++)
    {
        ll tmp;
        if(str[i]=='*')
            tmp=dfs(l,i)*dfs(i+1,r)%mod;
        else if(str[i]=='-')
            tmp=(dfs(l,i)*fac[r-i-1]-dfs(i+1,r)*fac[i-l]+mod)%mod;
        else if(str[i]=='+')
            tmp=(dfs(l,i)*fac[r-i-1]+dfs(i+1,r)*fac[i-l])%mod;

        res=(res+tmp*c[r-l-1][i-l]+mod)%mod;
    }
    return res;
}

int main()
{
    int kase;
    freopen("in.txt","r",stdin);
    init();
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0; i<n; i++)
            scanf("%lld",&a[i]);
        scanf("%s",str);

        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                dp[i][j]=mod;

        cout<<(dfs(0,n-1)+mod)%mod<<endl;
    }
    return 0;
}
/*

3
3 2 1
-+
5
1 4 6 8 3
+*-*
5
1 1 1 1 1
****

*/

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-03 22:26:21

HDU--5396(区间dp+排列组合)的相关文章

hdu 5396 区间dp+组合

http://acm.hdu.edu.cn/showproblem.php?pid=5396 Problem Description Teacher Mai has n numbers a1,a2,?,anand n?1 operators("+", "-" or "*")op1,op2,?,opn?1, which are arranged in the form a1 op1 a2 op2 a3 ? an. He wants to erase

hdu 5151 Sit sit sit(区间dp+排列组合)

题目链接:hdu 5151 Sit sit sit 题意: 一共有并排N个椅子, N个学生依次去坐,同时满足3个条件就不能坐下去: 1,该椅子不在最左,不在最右. 2,该椅子左右都有人坐了. 3,左右的椅子不同颜色.求最后N个人都能坐下去,有多少不同的情况. 题解: 考虑区间dp,dp[i][j] = sum(dp[i][k-1] * dp[k+1][j] * c[j - i][k - i])其中满足(v[k-1]==v[k+1]) 表示i到j区间最后来坐k位置,乘组合是因为合并这两段区间的时候

【HDU】5151 Sit Sit Sit(区间DP+排列组合)

题目大意:可以查阅网站的中文翻译,就不说了,是第24场Best Coder 思路: 这道这道区间DP,我也开始觉得其实区间DP是一种应用型的思想,做这类题目一个重要的点是在于题目情景的把握,这道题的一个情景就是数学的排列组合问题. 首先应用根据小区间推出大区间的思路,我们可以先固定一个位置k,k位置是最后做的位置,那么我们要算出在这种情况下符合的方法数,假如k是头或者尾,那不用说, 此时的方法为dp[i+1][j]或者是dp[i][j-1]; 假如k是有邻居的,那我们就要考虑邻居的颜色,如果颜色

hdu5396 Expression 区间dp +排列组合

#include<stdio.h> #include<string> #include<map> #include<vector> #include<cmath> #include<stdlib.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; const int N=105; cons

HDU 5396 区间DP 数学 Expression

题意:有n个数字,n-1个运算符,每个运算符的顺序可以任意,因此一共有 (n - 1)! 种运算顺序,得到 (n - 1)! 个运算结果,然后求这些运算结果之和 MOD 1e9+7. 分析: 类比最优矩阵链乘,枚举区间[l, r]中最后一个运算符的位置k. 如果运算符为乘法的话,那么根据乘法分配率这个乘法会分配进去. 这个区间中一共有r - l个运算符,其中最后一个运算符已经定了是第k个,左区间[l, k]有k - l个运算符,右区间[k + 1, r]有 r - k - 1 个运算符. 而且左

hdu 5396 区间DP

Expression Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 482    Accepted Submission(s): 284 Problem Description Teacher Mai has n numbers a1,a2,?,anand n?1 operators("+", "-" o

【BZOJ】4559: [JLoi2016]成绩比较 计数DP+排列组合+拉格朗日插值

[题意]n位同学(其中一位是B神),m门必修课,每门必修课的分数是[1,Ui].B神碾压了k位同学(所有课分数<=B神),且第x门课有rx-1位同学的分数高于B神,求满足条件的分数情况数.当有一位同学的一门必修课分数不同时视为两种情况不同.n,m<=100,Ui<=10^9. [算法]计数DP+排列组合+拉格朗日插值 [题解]把分数作为状态不现实,只能逐门课考虑. 设$f[i][j]$表示前i门课,有j个同学被碾压的情况数,则有: $$f[i][j]=g(i)\cdot\sum_{k=j

【noi 2.6_9288】&amp;【hdu 1133】Buy the Ticket(DP / 排列组合 Catalan+高精度)

题意:有m个人有一张50元的纸币,n个人有一张100元的纸币.他们要在一个原始存金为0元的售票处买一张50元的票,问一共有几种方案数. 解法:(学习了他人的推导后~) 1.Catalan数的应用7的变形.(推荐阅读:http://www.cnblogs.com/chenhuan001/p/5157133.html).P.S.不知我之前自己推出的公式“C(n,m)*C(2*m,m)/(m+1)*P(n,n)*P(m,m)”是否是正确的. (1)在不考虑m人和n人本身组内的排列时,总方案数为C(m+

LightOJ1005 Rooks(DP/排列组合)

题目是在n*n的棋盘上放k个车使其不互相攻击的方案数. 首先可以明确的是n*n最多只能合法地放n个车,即每一行都指派一个列去放车. dp[i][j]表示棋盘前i行总共放了j个车的方案数 dp[0][0]=1 转移就是从第i-1行转移到第i行,对于第i行要嘛放上一个车要嘛不放,放的话有n-j-1种方法.即dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(n-j-1). 1 #include<cstdio> 2 #include<cstring> 3 using na