HDU4632 Poj2955 括号匹配 整数划分 P1880 [NOI1995]石子合并 区间DP总结
题意:给定一个字符串 输出回文子序列的个数 一个字符也算一个回文
很明显的区间dp 就是要往区间小的压缩!
#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s)
#define LL long long
#define REP(i,N) for(int i=0;i<(N);i++)
#define CLR(A,v) memset(A,v,sizeof A)
//////////////////////////////////
#define N 1005
#define inf 0x3f3f3f3f
#define mod 10007
int dp[N][N]; int main()
{
int cas;
cin>>cas;
char s[];
int kase=;
while(cas--)
{
CLR(dp,);
RS(s+);
int n=strlen(s+);
rep(i,,n)
dp[i][i]=;//长度为一的区间肯定是一个回文 rep(i,,n)
for(int j=i-;j>=;j--)//这样保证了 len从小到大!
{
dp[j][i]=(dp[j+][i]+dp[j][i-]-dp[j+][i-]+mod)%mod;//容斥原理 反正就是要将dp往区间短的转移
if(s[i]==s[j])
dp[j][i] = (dp[j][i]+dp[j+][i-]++mod)%mod;//如果两边相等 那么这两个数可与i+1 到j-1里所有回文序列组成一个回文序列 且它们自己也是一个回文序列所以要加一
}
printf("Case %d: %d\n",++kase,dp[][n]);
}
}
Poj2955 括号匹配(一)
给出一个的只有'(',')','[',']'四种括号组成的字符串,求 最多 有多少个括号满足题目里所描述的完全匹配。
状态转移方程:dp[i][j]表示第i~j个字符间的最大匹配字符数。
if(s[i] 与 s[j]匹配) dp[i][j] = d[[i+1][j-1] +2;
dp[i][j] = max(dp[i][j],dp[i][k]+dp[k+1][j]);
#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s)
#define LL long long
#define REP(i,N) for(int i=0;i<(N);i++)
#define CLR(A,v) memset(A,v,sizeof A)
//////////////////////////////////
#define N 1005
#define inf 0x3f3f3f3f
#define mod 10007
int dp[N][N]; int main()
{
char s[N];
while(RS(s+)==)
{
CLR(dp,);
int n=strlen(s+);
rep(i,,n-)
// if(s[i]=='('&&s[i+1]==')'||s[i]=='['&&s[i+1]==']')
// dp[i][i+1]=1;
rep(len,,n)
for(int i=,j=i+len-;j<=n;i++,j=i+len-)
{
if((s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']'))
dp[i][j] = dp[i+][j-]+; //如果匹配,先更新 for(int k = i;k<j;k++)//区间合并
{//k<j
dp[i][j] = max(dp[i][j],dp[i][k]+dp[k+][j]);
}
}
cout<<dp[][n]<<endl;
}
}
整数划分
给出一个数n,要求在n的数位间插入(m-1)个乘号,将n分成了m段,求这m段的最大乘积。
样例输入
2
111 2
1111 2
样例输出
11
121
状态转移方程为
dp[i][j]=max(dp[i][j],dp[k][j-1]*num[k+1][i])
其中num[i][j]表示从s[i]到s[j]这段连续区间代表的数值。
#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s)
#define LL long long
#define REP(i,N) for(int i=0;i<(N);i++)
#define CLR(A,v) memset(A,v,sizeof A)
//////////////////////////////////
#define N 1005
#define inf 0x3f3f3f3f
#define mod 10007
int dp[N][N];
int num[ N][N];
int main()
{
char s[];
int n,m;
RS(s+);
RI(m);
n=strlen(s+);
rep(i,,n)
{
num[i][i]=s[i]-'';
rep(j,i+,n)
num[i][j]=num[i][j-]*+s[j]-'';
}
rep(i,,n)
dp[i][]=num[][i]; rep(j,,m-)//乘号一个个放入 因为每次dp[i][j] 由dp[i][j-1]转移而来 所以要j从小到大开始枚举 就像之前的要len从小到大开始枚举 因为每一个长区间取决于短区间
rep(i,j+,n)
rep(k,j,i-)
dp[i][j]=max(dp[i][j],dp[k][j-]*num[k+][i] );
cout<<dp[n][m-];
}
石子合并
题目描述
在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.
输入输出格式
输入格式:
数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.
输出格式:
输出共2行,第1行为最小得分,第2行为最大得分.
输入输出样例
4
4 5 9 4
43
54 特意去学习了区间dp 发现是区间dp入门题:石子划分的加强版 (当然 这题也是入门题) 对比那题 只是把链变成了环 可以得到区间dp的方程:
f[i][j] = max(f[i][k] + f[k+1][j] + 合并付出的代价) 这里的代价是 i到j的所有石子合 如果对dp顺序没有加以设计的话 很容易写出
i=1 to 10,j=1 to 10,k=1 to 9.当i=1,j=5,k=3时,显然状态f[k+1][j]没有结果。 f[4][5]的结果为i=4 j=5时求出的
所以区间dp对执行顺序是有考究的:
枚举j-i(也就是len),并在j-i中枚举k。这样,就能保证地推的正确
#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s)
#define LL long long
#define REP(i,N) for(int i=0;i<(N);i++)
#define CLR(A,v) memset(A,v,sizeof A)
//////////////////////////////////
#define N 300
#define inf 0x3f3f3f3f
int a[N];
int dp1[N][N];//max
int dp2[N][N];//min
int s[N];
int main()
{
int n;
RI(n);
rep(i,,n)
RI(a[i]),a[i+n]=a[i]; rep(i,,*n)
s[i]=s[i-]+a[i];
rep(len,,n-)
{
for(int i=,j=i+len;i<=*n&&j<=*n;i++,j=i+len )
{
dp2[i][j]=inf;//注意求最小值的初始化
for(int k=i;k<j;k++)
{
dp1[i][j]=max(dp1[i][j],dp1[i][k]+dp1[k+][j]+s[j]-s[i-] );
dp2[i][j]=min(dp2[i][j],dp2[i][k]+dp2[k+][j]+s[j]-s[i-] );
}
}
}
int ans1=;
int ans2=inf;
rep(i,,n)
{
ans1=max(ans1,dp1[i][i+n-]);//注意减一
ans2=min(ans2,dp2[i][i+n-]);
}
cout<<ans2<<endl<<ans1;
return ;
}
HDU4632 Poj2955 括号匹配 整数划分 P1880 [NOI1995]石子合并 区间DP总结的更多相关文章
- P1880 [NOI1995]石子合并[区间dp+四边形不等式优化]
P1880 [NOI1995]石子合并 丢个地址就跑(关于四边形不等式复杂度是n方的证明) 嗯所以这题利用决策的单调性来减少k断点的枚举次数.具体看lyd书.这部分很生疏,但是我还是选择先不管了. # ...
- P1880 [NOI1995]石子合并 区间dp
P1880 [NOI1995]石子合并 #include <bits/stdc++.h> using namespace std; ; const int inf = 0x3f3f3f3f ...
- P1880 [NOI1995]石子合并 区间dp+拆环成链
思路 :一道经典的区间dp 唯一不同的时候 终点和起点相连 所以要拆环成链 只需要把1-n的数组在n+1-2*n复制一遍就行了 #include<bits/stdc++.h> usi ...
- 洛谷 P1880 [NOI1995] 石子合并(区间DP)
传送门 https://www.cnblogs.com/violet-acmer/p/9852294.html 题解: 这道题是石子合并问题稍微升级版 这道题和经典石子合并问题的不同在于,经典的石子合 ...
- P1880 [NOI1995]石子合并[环形DP]
题目来源:洛谷 题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1个算法,计算出将 ...
- 区间DP小结 及例题分析:P1880 [NOI1995]石子合并,P1063 能量项链
区间类动态规划 一.基本概念 区间类动态规划是线性动态规划的拓展,它在分阶段划分问题时,与阶段中元素出现的顺序和由前一阶段的那些元素合并而来由很大的关系.例如状态f [ i ][ j ],它表示以已合 ...
- 洛谷 P1880 [NOI1995]石子合并 题解
P1880 [NOI1995]石子合并 题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试 ...
- 【区间dp】- P1880 [NOI1995] 石子合并
记录一下第一道ac的区间dp 题目:P1880 [NOI1995] 石子合并 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 代码: #include <iostream> ...
- 洛谷P1880 [NOI1995]石子合并 纪中21日c组T4 2119. 【2016-12-30普及组模拟】环状石子归并
洛谷P1880 石子合并 纪中2119. 环状石子归并 洛谷传送门 题目描述1 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石 ...
随机推荐
- 第一天进入博客这个神奇的领域 在此%%%erosun
第一条博客水一水 等会要找一下调博客模板 独立动手,丰衣足食
- 前端学习 -- Html&Css -- 相对定位 绝对定位 固定定位
相对定位 - 定位指的就是将指定的元素摆放到页面的任意位置,通过定位可以任意的摆放元素. - 通过position属性来设置元素的定位. -可选值: static:默认值,元素没有开启定位: rela ...
- 前端学习 -- Css -- 否定伪类
语法::not(.选择器) 作用:可以从已选中的元素中剔除出某些元素. <!DOCTYPE html> <html> <head> <meta charset ...
- Win32+API学习笔记:创建基本的窗口控件
创建一个标签 CreateWindowEx(0, "static", "姓名:", ...
- ubuntu,centor 安装apache bench
ab全称为:apache bench. 是apache自带的压力测试工具.ab非常实用,它不仅可以对apache服务器进行网站访问压力测试,也可以对或其它类型的服务器进行压力测试.比如nginx.to ...
- Redis记录-Redis命令
Redis命令是用于在Redis服务器上执行一些操作.要在Redis服务器上运行命令,需要一个Redis客户端.Redis客户端在Redis包中有提供,这个包在我们前面的安装教程中就有安装过了. 语法 ...
- 分布式锁--Redis小试牛刀
参考文章: Redis分布式锁的正确实现方式 分布式锁看这篇就够了 在这两篇文章的指引下亲测 Redis分布式锁 引言 分布式系统一定会存在CAP权衡问题,所以才会出现分布式锁 什么是CAP理论? 为 ...
- 使用JavaScript缓存图片
在JS中,为了让图片缓存起来,客户端JS定义了一个API,首先利用Image()构造函数来创建一个屏幕外图片对象,之后将该对象的src属性设置 期望的URL,由于图片元素并没有添加到文档中,因此它是不 ...
- 20155328 2016-2017-2 《Java程序设计》 第8周学习总结
20155328 2016-2017-2 <Java程序设计> 第8周学习总结 教材学习内容总结 NIO与NIO2 认识NIO 相对于IO,NIO可以让你设定缓冲区容量,在缓冲区中对感兴趣 ...
- python中的__enter__ __exit__
我们前面文章介绍了迭代器和可迭代对象,这次介绍python的上下文管理.在python中实现了__enter__和__exit__方法,即支持上下文管理器协议.上下文管理器就是支持上下文管理器协议的对 ...