【区间dp+组合数+数学期望】Expression
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,所以要用快速幂。
快速幂模板
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的更多相关文章
- [2013山东ACM]省赛 The number of steps (可能DP,数学期望)
The number of steps nid=24#time" style="padding-bottom:0px; margin:0px; padding-left:0px; ...
- CSU 1290 DP解决数学期望问题
题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1290 题目大意: 给定k个数,每次可以生成0-N-1中的任何一个数,k个数中出现不同的整 ...
- bzoj-3450 Easy概率DP 【数学期望】
Description 某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(我们来简化一下这个游戏的规则有n次点击要做,成功了就是o,失败了就是x,分数是按comb计算的,连续a ...
- poj 2057 树形DP,数学期望
题目链接:http://poj.org/problem?id=2057 题意:有一只蜗牛爬上树睡着之后从树上掉下来,发现后面的"房子"却丢在了树上面, 现在这只蜗牛要求寻找它的房子 ...
- HDU 4405 Aeroplane chess(概率dp,数学期望)
题目 http://kicd.blog.163.com/blog/static/126961911200910168335852/ 根据里面的例子,就可以很简单的写出来了,虽然我现在还是不是很理解为什 ...
- 【整理】简单的数学期望和概率DP
数学期望 P=Σ每一种状态*对应的概率. 因为不可能枚举完所有的状态,有时也不可能枚举完,比如抛硬币,有可能一直是正面,etc.在没有接触数学期望时看到数学期望的题可能会觉得很阔怕(因为我高中就是这么 ...
- 2015暑假多校联合---Expression(区间DP)
题目链接 http://acm.split.hdu.edu.cn/showproblem.php?pid=5396 Problem Description Teacher Mai has n numb ...
- HDU 5396 Expression(DP+组合数)(详解)
题目大意: 给你一个n然后是n个数. 然后是n-1个操作符,操作符是插入在两个数字之间的. 由于你不同的运算顺序,会产生不同的结果. 比如: 1 + 1 * 2 有两种 (1+1)*2 或者 ...
- 数学期望和概率DP题目泛做(为了对应AD的课件)
题1: Uva 1636 Headshot 题目大意: 给出一个000111序列,注意实际上是环状的.问是0出现的概率大,还是当前是0,下一个还是0的概率大. 问题比较简单,注意比较大小: A/C & ...
随机推荐
- 四大开源协议比较:BSD、Apache、GPL、LGPL【转载】
四大开源协议原文链接 本文参考文献:http://www.fsf.org/licensing/licenses/ 现今存在的开源协议很多,而经过Open Source Initiative组织通过批准 ...
- AngularJS开发最常犯的10个错误
简介 AngularJS是目前最为活跃的Javascript框架之一,AngularJS的目标之一是简化开发过程,这使得AngularJS非常善于构建小型app原型,但AngularJS对于全功能的客 ...
- Webform 内置对象 Session对象、Application全局对象,ViewState
Session 每台电脑访问服务器,都有独立的session,key值都一样,内容不一样. 1.session保存在服务器上. 2.session没有持久性,保存周期就是20分钟. 重点: sessi ...
- Asp.Net中调用存储过程并返回输出参数
/// <summary> /// 调用存储过程返回参数 /// </summary> /// <param name="orderId">&l ...
- 掌握Spark机器学习库-07-最小二乘法
1)最小化残差平方和 2)原理,推导过程 3)例子
- [转] 以超级管理员身份运行bat
(转自:以超级管理员身份运行bat - lishirong 原文日期:2013.07.04) 废话不多说,直接上代码: -------------------------------------- ...
- Linux下 SpringBoot jar项目后台运行、查看、停用
运行java jar: nohup java -jar **-0.0.1-SNAPSHOT.jar & 查看进程: 采用top或者ps aux命令.一般 如果后台是springboot,jar ...
- CE工具里自带的学习工具--第五关
图解: 此时会弹出一个对话框,选择是就可以了,最终会看到:
- 在vue中场景,循环行,点击当前行编辑数据
当前列表 点击编辑,行变为编辑框. <Row style="color:#999;margin-bottom:11px"> <Row style="ma ...
- python msg_box
转自:http://www.cnblogs.com/otfsenter/ # _*_ coding: utf-8 _*_ # @Time : 2017/3/27 17:39 # @Author : o ...