hdu5396 Expression 区间dp +排列组合
来源:互联网 发布:桃源恋歌动作数据 编辑:程序博客网 时间:2024/06/07 15:34
#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;
const int MOD=1e9+7;
int n;
int a[N];
char ch[N];
void rd(int&x){
char ch;
for(ch=getchar();ch<'0' || ch>'9';ch=getchar());
x=0;
for(;ch>='0' && ch<='9';ch=getchar()) x=x*10+ch-'0';
}
long long res;
long long sum[N][N][N]; /*sum[i][j][k]表示区间i到j最后一个取第k个符号的答案和 ,sum[i][j][n+1]表示区间i到的答案总和*/
long long A[N];
long long calc(long long x,long long y,char c){
if(c=='+') return (x+y)%MOD;
else if(c=='-') return (x-y+MOD)%MOD;
else return (x*y)%MOD;
}
long long C[N][N];
void solve(){
memset(sol,0,sizeof sol);
memset(sum,0,sizeof sum);
for(int i=1;i<=n;i++){
sum[i][i][n+1]=a[i];
}
for(int i=1;i<n;i++){
sum[i][i+1][n+1]=sum[i][i+1][i]=calc(a[i],a[i+1],ch[i]);
}
for(int j=3;j<=n;j++)
for(int i=1;i+j-1<=n;i++){
int l=i,r=i+j-1;
for(int k=l;k<r;k++){
if(ch[k]=='+'){
/*
第k个符号左边 第l到k个数字,这个区间的方案个数 A[k-l] sum[l][k][n+1] l到k的和
第k个符号右边 第k+1到r个数字 这个区间的方案个数 A[r-k-1] sum[k+1][r][n+1] k+1到r的和
设左边 A[k-l]个值 a1,a2, ........ ai指的都是左边这个区间由某一顺序得到的一个值,可以将它和一个操作序列等同
设右边 A[r-k-1] 个值 b1,b2, ........
(a1+a2........) + (b1,b2.............) 对于每个a,被加A[r-k-1]次 ,对于每个b,被加A[k-l]次
减法同理
乘法特殊一点
(a1+a2........) * (b1,b2.............) 乘法分配率,直接将两部分的总和相乘即可
*/
sum[l][r][k]=(sum[l][k][n+1]*A[r-k-1]+sum[k+1][r][n+1]*A[k-l])%MOD;
}else if(ch[k]=='-'){
sum[l][r][k]=(sum[l][k][n+1]*A[r-k-1]-sum[k+1][r][n+1]*A[k-l])%MOD;
sum[l][r][k]=(sum[l][r][k]+MOD)%MOD;
}else{
sum[l][r][k]=(sum[l][k][n+1]*sum[k+1][r][n+1])%MOD;
}
/*
之前算的是(左边的选择序列)+(右边的选择序列),但是左右两边也有先后,再乘个组合数,比赛时这个想了好久才想到
对于上面的每个ai和bj,他们在 遇到区间的最后一个操作符号后,需要再乘以一个组合数,因为之前的ai和bj是这样的
ai:(操作1,操作2,操作3.。。。。操作n)+ bj:(操作n+1,操作n+2,操作n+3.。。。。),但是不一定是ai的操作序列全在前面的,至于为什是组合不是排列
因为每个ai和bj自己内部已经是有序了的,感觉这样讲的挺清楚了吧,自己比赛的时候这里卡了挺就久的,但是仔细想一下,还是可以明白的
*/
sum[l][r][k]=(sum[l][r][k]*C[r-l-1][k-l])%MOD;
sum[l][r][n+1]=(sum[l][r][n+1]+sum[l][r][k])%MOD;
sum[l][r][n+1]=(sum[l][r][n+1]+MOD)%MOD;
}
}
printf("%I64d\n",sum[1][n][n+1]);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("aaa","r",stdin);
#endif
int T;
int q;
A[0]=1;/*A是全排列 C是组合 ,预处理这两个*/
for(int i=1;i<N;i++) A[i]=(A[i-1]*i)%MOD;
for(int i=0;i<N;i++) C[i][0]=1;
for(int i=1;i<N;i++) for(int j=0;j<=i;j++) {
if(j==0 || j==i) C[i][j]=1;
else C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
}
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%s",ch+1);
solve();
}
return 0;
}
#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;
const int MOD=1e9+7;
int n;
int a[N];
char ch[N];
void rd(int&x){
char ch;
for(ch=getchar();ch<'0' || ch>'9';ch=getchar());
x=0;
for(;ch>='0' && ch<='9';ch=getchar()) x=x*10+ch-'0';
}
long long res;
long long sum[N][N][N]; /*sum[i][j][k]表示区间i到j最后一个取第k个符号的答案和 ,sum[i][j][n+1]表示区间i到的答案总和*/
long long A[N];
long long calc(long long x,long long y,char c){
if(c=='+') return (x+y)%MOD;
else if(c=='-') return (x-y+MOD)%MOD;
else return (x*y)%MOD;
}
long long C[N][N];
void solve(){
memset(sol,0,sizeof sol);
memset(sum,0,sizeof sum);
for(int i=1;i<=n;i++){
sum[i][i][n+1]=a[i];
}
for(int i=1;i<n;i++){
sum[i][i+1][n+1]=sum[i][i+1][i]=calc(a[i],a[i+1],ch[i]);
}
for(int j=3;j<=n;j++)
for(int i=1;i+j-1<=n;i++){
int l=i,r=i+j-1;
for(int k=l;k<r;k++){
if(ch[k]=='+'){
/*
第k个符号左边 第l到k个数字,这个区间的方案个数 A[k-l] sum[l][k][n+1] l到k的和
第k个符号右边 第k+1到r个数字 这个区间的方案个数 A[r-k-1] sum[k+1][r][n+1] k+1到r的和
设左边 A[k-l]个值 a1,a2, ........ ai指的都是左边这个区间由某一顺序得到的一个值,可以将它和一个操作序列等同
设右边 A[r-k-1] 个值 b1,b2, ........
(a1+a2........) + (b1,b2.............) 对于每个a,被加A[r-k-1]次 ,对于每个b,被加A[k-l]次
减法同理
乘法特殊一点
(a1+a2........) * (b1,b2.............) 乘法分配率,直接将两部分的总和相乘即可
*/
sum[l][r][k]=(sum[l][k][n+1]*A[r-k-1]+sum[k+1][r][n+1]*A[k-l])%MOD;
}else if(ch[k]=='-'){
sum[l][r][k]=(sum[l][k][n+1]*A[r-k-1]-sum[k+1][r][n+1]*A[k-l])%MOD;
sum[l][r][k]=(sum[l][r][k]+MOD)%MOD;
}else{
sum[l][r][k]=(sum[l][k][n+1]*sum[k+1][r][n+1])%MOD;
}
/*
之前算的是(左边的选择序列)+(右边的选择序列),但是左右两边也有先后,再乘个组合数,比赛时这个想了好久才想到
对于上面的每个ai和bj,他们在 遇到区间的最后一个操作符号后,需要再乘以一个组合数,因为之前的ai和bj是这样的
ai:(操作1,操作2,操作3.。。。。操作n)+ bj:(操作n+1,操作n+2,操作n+3.。。。。),但是不一定是ai的操作序列全在前面的,至于为什是组合不是排列
因为每个ai和bj自己内部已经是有序了的,感觉这样讲的挺清楚了吧,自己比赛的时候这里卡了挺就久的,但是仔细想一下,还是可以明白的
*/
sum[l][r][k]=(sum[l][r][k]*C[r-l-1][k-l])%MOD;
sum[l][r][n+1]=(sum[l][r][n+1]+sum[l][r][k])%MOD;
sum[l][r][n+1]=(sum[l][r][n+1]+MOD)%MOD;
}
}
printf("%I64d\n",sum[1][n][n+1]);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("aaa","r",stdin);
#endif
int T;
int q;
A[0]=1;/*A是全排列 C是组合 ,预处理这两个*/
for(int i=1;i<N;i++) A[i]=(A[i-1]*i)%MOD;
for(int i=0;i<N;i++) C[i][0]=1;
for(int i=1;i<N;i++) for(int j=0;j<=i;j++) {
if(j==0 || j==i) C[i][j]=1;
else C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
}
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%s",ch+1);
solve();
}
return 0;
}
0 0
- hdu5396 Expression 区间dp +排列组合
- 【区间dp】hdu5396 Expression
- hdu5396(2015多校9)--Expression(区间dp)
- hdu5396(区间DP)
- HDU5396 Expressions(区间DP)
- hdu5396(区间dp)
- HDU 5396 Expression(区间DP,排列组合)
- hdu5396(区间dp+组合数)
- hdu5396 Expression
- hdu5396 2015多校第九场 区间dp
- hdu 5396 Expression 区间DP+排列组合 2015 Multi-University Training Contest 9
- hdu 5151区间dp+排列组合
- HDU 5396 - Expression(区间DP)
- HDU 5396 Expression 区间DP
- HDU--5396(区间dp+排列组合)
- HDU 5396 Expression (区间dp)
- HDU 5396 Expression (区间DP)
- HDU 5396 Expression (数学期望+区间DP)
- python中的有序字典OrderedDict
- category和protocol 第五天稍晚了一些。
- 关于double类型数字相加位数发生变化的问题
- Travelling Salesman Problem (hdu 5402 模拟)
- Android开源项目汇总
- hdu5396 Expression 区间dp +排列组合
- HDU 3255 题解 线段树+扫描线
- Linux基础篇
- iOS OC Label 详解
- gpgpu review
- 我第一个Python教程笔记
- 【多校第9场】【组合数学】【区间dp】【Expression】
- R语言基础绘图包--控制axis label位置--par(mgp)与mtext
- 【套汇】【bell-ford变形】