https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/I

【题意】

给定n个操作数和n-1个操作符,组成一个数学式子。每次可以选择两个相邻操作数及中间的操作符进行运算,如a-b变成一个数(a-b),直到这个式子变成一个数。同一个初始式子可以进行不同的操作,最后的结果也可能不同。最后求不同操作得到结果的和(mod 1000 000 007)

对于两个操作,只要存在一步是不同的,这两个操作就被认为是不同的。

【思路】

总体思路是区间dp,对于dp[i][j],枚举k(i<=k<j),考察dp[i][k]和dp[k+1][j]

具体做的时候可以分别考虑*,+,-三种运算,用组合数学;

还有一种非常非常巧妙的办法:数学期望!

组合数学:

比较明显的区间dp,令dp[l][r]为闭区间[l,r]的所有可能的结果和,考虑最后一个符号的位置k,k必须在l,r之间,则l≤k<r,dp[l][r]=Σ{dp[l][k]?dp[k+1][r]}*(r-l-1)!/[(k-l)!(r-k-1)!],其中(r-l-1)!/[(k-l)!(r-k-1)!]表示从左区间和右区间选择符号的不同方法总数(把左右区间看成整体,那么符号的选择在整体间也有顺序,内部的顺序不用管,那是子问题需要考虑的),相当于(k-l)个0和(r-k-1)个1放一起的不同排列方法总数。

对花括号里面的‘?‘分为三种情况:

(1)‘+‘  假设左区间有x种可能的方法,右区间有y种可能的方法,由于分配律的存在,左边的所有结果和会重复计算y次,右边的所有结果和会重复计算x次,而左边共(k-l)个符号,右边共(r-k-1)个符号,所以合并后的答案dp[l][r]=dp[l][k]*(r-k-1)!+dp[k+1][r]*(k-l)!

(2)‘-‘   与‘+‘类似

(3)‘*‘   由分配律,合并后的答案dp[l][r]=dp[l][k]*dp[k+1][r]

数学期望:

如果将这个过程随机化,即每次等概率地选取相邻两项合并,

记dp[i][j]为随机合并第i个到第j个数字这一段的表达式之后结果的期望,

根据期望的线性可加性,状态转移方程为

dp[i][j]=(sigma_(k=i~j-1)(dp[i][k]?dp[k+1][j]))/(j-i),

其中"?"表示第k个数与第k+1个数之间的运算符,

那么dp[1][n]即为随机合并整个表达式之后结果的期望,

乘上方案数(n-1)!即为所求的总和,

由于是取模意义下的运算,转移方程中的除法要用逆元代替,

复杂度O(n^3)。

【Accepted】

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath> using namespace std;
typedef long long ll;
const int maxn=1e2+;
const ll mod=1e9+;
ll a[maxn];
char op[maxn];
ll dp[maxn][maxn];
ll fpow(ll x,ll n)
{
ll res=1LL;
while(n)
{
if(n&)
{
res=(res*x)%mod;
}
x=(x*x)%mod;
n>>=;
}
return res;
}
ll fact[maxn];
ll nfact[maxn];
int n;
void init()
{
fact[]=1LL;
for(int i=;i<maxn;i++)
{
fact[i]=(fact[i-]*(ll)i)%mod;
}
nfact[]=1LL;
for(int i=;i<maxn;i++)
{
nfact[i]=fpow(fact[i],mod-);
}
}
int main()
{
init();
while(~scanf("%d",&n))
{
memset(dp,,sizeof(dp));
for(int i=;i<n;i++)
{
cin>>a[i];
}
scanf("%s",op);
for(int i=;i<n;i++)
{
dp[i][i]=a[i];
}
for(int l=;l<n;l++)
for(int i=;i+l<n;i++)
{
int j=i+l;
for(int k=i;k<j;k++)
{
ll add;
if(op[k]=='+')
{
add=(dp[i][k]*fact[j--k]%mod+dp[k+][j]*fact[k-i]%mod)%mod;
}
else if(op[k]=='-')
{
add=(dp[i][k]*fact[j--k]%mod-dp[k+][j]*fact[k-i]%mod+mod)%mod;
}
else
{
add=(dp[i][k]*dp[k+][j]%mod)%mod;
}
add=(add*fact[l-]%mod*nfact[j--k]%mod*nfact[k-i]%mod)%mod;
dp[i][j]=(dp[i][j]+add)%mod;
}
}
cout<<dp[][n-]<<endl; }
return ;
}

区间dp+组合数

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath> using namespace std;
typedef long long ll;
const ll md=1e9+;
ll fpow(ll x,ll n)
{
ll res=1LL;
while(n)
{
if(n&)
{
res=(res*x)%md;
}
x=(x*x)%md;
n>>=;
}
return res;
}
const int maxn=1e2+;
ll a[maxn];
char op[maxn];
ll dp[maxn][maxn];
ll fact[maxn];
void init()
{
fact[]=1LL;
for(int i=;i<maxn;i++)
{
fact[i]=(fact[i-]*(ll)i)%md;
}
}
int n;
int main()
{
init();
while(~scanf("%d",&n))
{
memset(dp,,sizeof(dp));
for(int i=;i<n;i++)
{
cin>>a[i];
}
scanf("%s",op);
for(int i=;i<n;i++)
{
dp[i][i]=a[i];
}
for(int l=;l<n;l++)
{
for(int i=;i+l<n;i++)
{
int j=i+l;
for(int k=i;k<j;k++)
{
ll add;
if(op[k]=='+')
{
add=(dp[i][k]+dp[k+][j])%md;
}
else if(op[k]=='-')
{
add=(dp[i][k]-dp[k+][j]+md)%md;
}
else
{
add=(dp[i][k]*dp[k+][j])%md;
}
dp[i][j]=(dp[i][j]+add)%md;
}
dp[i][j]=(dp[i][j]*fpow(l,md-))%md;
}
}
ll ans=(dp[][n-]*fact[n-])%md;
cout<<ans<<endl;
}
return ;
}

区间dp+数学期望(随机化过程,期望的线性可加性)

【知识点】

1. 取模意义下的除法不能直接除,要用逆元代替。根据费马小定理,a^(p-1)=1(mod p),所以a^(p-2)=(1/a)(mod p),所以a的逆元就是a^p-2。通常p是一个很大的素数,如经常见到的1e9+7,所以要用快速幂。

快速幂模板

fastpow

 ll fpow(ll x,ll n)
{
ll res=1LL;
while(n)
{
if(n&)
{
res=(res*x)%mod;
}
x=(x*x)%mod;
n>>=;
}
return res;
}

2. 组合数C(i,j)有两种算法:
第一种:

fac(i+j)*nfac(i)*nfac(j)
//其中nfac(i)=fastpow(fac(i),mod-2)

第二种:

C[][]=;
for (int i=;i<;i++)
{
C[i][]=;
for (int j=;j<=i;j++)
{
C[i][j]=(C[i-][j-]+C[i-][j])%md;
}
}

3. 在取模运算下,要注意减法,a-b通常要写成(a-b+md)%md

总之注意不要算出负数

【区间dp+组合数+数学期望】Expression的更多相关文章

  1. [2013山东ACM]省赛 The number of steps (可能DP,数学期望)

    The number of steps nid=24#time" style="padding-bottom:0px; margin:0px; padding-left:0px; ...

  2. CSU 1290 DP解决数学期望问题

    题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1290 题目大意: 给定k个数,每次可以生成0-N-1中的任何一个数,k个数中出现不同的整 ...

  3. bzoj-3450 Easy概率DP 【数学期望】

    Description 某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(我们来简化一下这个游戏的规则有n次点击要做,成功了就是o,失败了就是x,分数是按comb计算的,连续a ...

  4. poj 2057 树形DP,数学期望

    题目链接:http://poj.org/problem?id=2057 题意:有一只蜗牛爬上树睡着之后从树上掉下来,发现后面的"房子"却丢在了树上面, 现在这只蜗牛要求寻找它的房子 ...

  5. HDU 4405 Aeroplane chess(概率dp,数学期望)

    题目 http://kicd.blog.163.com/blog/static/126961911200910168335852/ 根据里面的例子,就可以很简单的写出来了,虽然我现在还是不是很理解为什 ...

  6. 【整理】简单的数学期望和概率DP

    数学期望 P=Σ每一种状态*对应的概率. 因为不可能枚举完所有的状态,有时也不可能枚举完,比如抛硬币,有可能一直是正面,etc.在没有接触数学期望时看到数学期望的题可能会觉得很阔怕(因为我高中就是这么 ...

  7. 2015暑假多校联合---Expression(区间DP)

    题目链接 http://acm.split.hdu.edu.cn/showproblem.php?pid=5396 Problem Description Teacher Mai has n numb ...

  8. HDU 5396 Expression(DP+组合数)(详解)

    题目大意: 给你一个n然后是n个数. 然后是n-1个操作符,操作符是插入在两个数字之间的. 由于你不同的运算顺序,会产生不同的结果. 比如: 1 + 1 * 2 有两种  (1+1)*2   或者   ...

  9. 数学期望和概率DP题目泛做(为了对应AD的课件)

    题1: Uva 1636 Headshot 题目大意: 给出一个000111序列,注意实际上是环状的.问是0出现的概率大,还是当前是0,下一个还是0的概率大. 问题比较简单,注意比较大小: A/C & ...

随机推荐

  1. 转 Docker 组件如何协作?- 每天5分钟玩转容器技术(8)

    http://www.cnblogs.com/CloudMan6/p/6774519.html 记得我们运行的第一个容器吗?现在通过它来体会一下 Docker 各个组件是如何协作的. 容器启动过程如下 ...

  2. jmeter(七)函数

    JMeter函数是一些能够转化在测试树中取样器或者其他配置元件的域的特殊值.一个函数的调用就像这样:${_functionName(var1,var2,var3)},-functionName匹配函数 ...

  3. sdut1650I-Keyboard(dp)

    链接 题目大意就相当于 跟你一串字符串 让你截成k段 使总体的值最小 想法是递归的 递归太慢 可以转换为递推的 这样就有可以推出状态方程 dp[i][j] = max(dp[i][j],dp[i-1] ...

  4. framework7 点取消后还提交表单解决方案

    $$('form.ajax-submit').on('submitted', function (e) { var xhr = e.detail.xhr; // actual XHR object v ...

  5. Windowsforms 中对文件操作

    文件及文件夹操作: 引用命名空间:using system .IO; 1.File类: 创建:File.Create(路径);——返回FileStream FileStream fs = File.C ...

  6. iOS-UI控件之UIImageView

    contentMode属性 带有scale单词的:图片有可能会拉伸 UIViewContentModeScaleToFill 将图片拉伸至填充整个imageView 图片显示的尺寸跟imageView ...

  7. vue2.0自定义事件

    我们知道父组件是使用props传递数据给子组件,如果子组件要把数据传递回去,怎么办? 那就是要自定义事件!使用v-on绑定自定义事件 每个Vue实例都实现了事件接口(Events interface) ...

  8. 洛谷 P3371 【模板】单源最短路径(堆优化dijkstra)

    题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三 ...

  9. connection timeout 和command timeout

    每次对数据库连接时,我们有时候会碰到连接超时或者命令超时,这两个超时是不一样的.以ADO.NET为例,当客户端和服务器端连接时,碰到的超时情况主要有下面几种: ''' 当从连接池获取一个连接时,碰到超 ...

  10. pythno学习小结-替换python字典中的key值

    源: d={'a':1,'b':2,'c':3} 目标:key:'b'替换为'e' d={'a':1,'e':2,'c':3} 方法: d['e']=d.pop('b')