区间dp专题练习

题意

1.Equal Sum Partitions

? 这嘛东西,\(n^2\)自己写去

\[\
\]

\[\
\]

2.You Are the One

感觉自己智力被吊打

\(dp[i][j]\)表示 , 对于当前的一个空栈 , \(i\)到\(j\)这一段都出栈的最小花费

显然是长得一副区间(诡)dp(异)的样子 , 如何转移呢?(建议自己想想吧)

对于一个\(dp[i][j]\),因为这个\(i\)必须是最先入栈的 , 所以我们可以枚举它的出栈时间\(k\) , 那么总贡献就是

\[dp[i+1][k]+(k-i)*a[i]+sum[k+1..j] \cdot (k-i+1)
\]

即先出栈的\(i+1...k\)的贡献和+i自己的贡献+\(k+1..j\)这一段的贡献和它们被推迟\(k-i+1\)位产生的贡献

rep(i,1,n) rep(j,i+1,n) dp[i][j]=1e9;
rep(i,1,n) dp[i][i]=a[i];
drep(i,n,1)
rep(j,i,n)
rep(k,i,j)
dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]+(k-i)*a[i]+(k-i+1)*(s[j]-s[k]));

\[\
\]

\[\
\]

3.Groups

where is my head?

每个人的决策其实就是把一群人分成一组,所以可以直接一个个区间接上去

细节:满足条件的人大于\(R-L+1\)时要取\(min\)

区间dp?

rep(i,1,n) a[i]=rd(),b[i]=rd();
rep(i,0,n) rep(j,0,n) c[i][j]=0;
rep(i,0,n) dp[i]=0;
rep(i,1,n) c[a[i]][n-b[i]]++;
rep(i,0,n-1) rep(j,i+1,n) dp[j]=max(dp[j],dp[i]+min(j-i,c[i][j]));
printf("%d\n",dp[n]);

4.Sky Soldiers

又是假区间dp

const int N=1010;
const double eps=1e-6; int n,m;
map <int,double> M;
typedef map<int,double> ::iterator iter;
int p[N];
double x[N];
int cnt;
double dp[N][51];//前i个,放j个站
double sum[N][N]; int main(){
while(~scanf("%d%d",&n,&m)&&n&&m) {
M.clear();
rep(i,1,n) {
rep(j,1,rd()) {
int p=rd();
double x;scanf("%lf",&x);
M[p]+=x;
}
}
cnt=0;
for(iter it=M.begin();it!=M.end();++it) {
p[++cnt]=it->first;
x[cnt]=it->second;
}//暴力离散
double ans=1e11;
rep(i,0,cnt) rep(j,0,m) dp[i][j]=1e11;
rep(i,1,cnt) rep(j,1,cnt) sum[i][j]=sum[i][j-1]+x[j]*abs(p[i]-p[j]);//预处理便于算贡献
rep(i,1,cnt) dp[i][1]=sum[i][i];
rep(i,1,cnt) {
rep(j,1,m-1) if(dp[i][j]<1e10) {
rep(k,i+1,cnt) {
int mid=(p[i]+p[k])>>1;
mid=lower_bound(p+1,p+cnt+1,mid)-p;
double s=min(sum[i][mid]-sum[i][i]+sum[k][k]-sum[k][mid],sum[i][mid-1]-sum[i][i]+sum[k][k]-sum[k][mid-1]);//贡献
dp[k][j+1]=min(dp[k][j+1],dp[i][j]+s);
}
}
}
rep(i,1,cnt) ans=min(ans,dp[i][m]+sum[i][cnt]-sum[i][i]);
printf("%.2lf\n",ans);
}
}

\[\
\]

\[\
\]

5.Play Game

假区间dp again

\(dp[l1][r1][l2][r2]\)表示两个序列分别还剩下\(l1,r1\),\(l2,r2\)的答案 , 很基础但是有细节

int n,m;
int a[N],b[N];
int dp[N][N][N][N];
int sum1[N],sum2[N]; int main(){
rep(kase,1,rd()) {
n=rd();
rep(i,1,n) sum1[i]=a[i]=rd(),sum1[i]+=sum1[i-1];
rep(i,1,n) sum2[i]=b[i]=rd(),sum2[i]+=sum2[i-1];
memset(dp,0,sizeof dp);
drep(l1,n+1,1) rep(r1,l1-1,n) drep(l2,n+1,1) rep(r2,l2-1,n) {
if(l1>r1&&l2>r2) continue;
int s=1e9;
if(l1<=r1) s=min(s,min(dp[l1+1][r1][l2][r2],dp[l1][r1-1][l2][r2]));
if(l2<=r2) s=min(s,min(dp[l1][r1][l2+1][r2],dp[l1][r1][l2][r2-1]));
dp[l1][r1][l2][r2]=sum1[r1]-sum1[l1-1]+sum2[r2]-sum2[l2-1]-s;
}
printf("%d\n",dp[1][n][1][n]);
}
}

\[\
\]

\[\
\]

6.Two Rabbits

这个鬼题是真的惊了

首先肯定要接两倍数组断成链

然后我们分析题目性质,对于任意路径,互为重合逆子序列时最优

即跳跃路径为原序列的一个回文子序列时一定更优

若两只兔子的路径错开,那么一定可以向两边继续延伸

细节:一个点时回文长度为1,当跳跃总长小于n时答案要加一

int n,m;
int a[N];
int dp[N][N]; int main(){
srand(618);
while(~scanf("%d",&n)&&n){
rep(i,1,n) a[i]=a[i+n]=rd();
int ans=0;
memset(dp,0,sizeof dp);
rep(l,1,n) drep(i,n*2-l+1,1) {
int j=i+l-1;
if(a[i]==a[j]) dp[i][j]=dp[i+1][j-1]+2-(i==j);
else dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
ans=max(ans,dp[i][j]+(l<n));
}
printf("%d\n",ans);
}
}

\[\
\]

\[\
\]

7.Dire Wolf

这个题长得还是比较区间dp的

表示自己的转移错得离谱都过掉了。。。

正确的转移方法和T2有点类似,即枚举最后一个杀死的狼,加上前后直接转移

int n,m;
int a[N],b[N];
int dp[N][N]; int main(){
rep(kase,1,rd()){
rep(i,1,n=rd()) a[i]=rd();
rep(i,1,n) b[i]=rd();b[n+1]=a[n+1]=0;
//memset(dp,10,sizeof dp);
drep(i,n,1) rep(j,i,n) {
dp[i][j]=1e9;
if(i==j) dp[i][j]=a[i]+b[i-1]+b[i+1];
else rep(k,i,j) dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+a[k]+b[i-1]+b[j+1]);
//第k只狼最后杀死,贡献分开算
}
printf("Case #%d: %d\n",kase,dp[1][n]);
}
}

\[\
\]

\[\
\]

8.Dylans loves sequence

这个题令我不想说话


int n,m;
int a[N],b[N],cnt;
int s[N],ans[N][N];
void Add(int p,int x){
while(p<=n) s[p]+=x,p+=p&-p;
}
int Que(int p){
int res=0;
while(p) res+=s[p],p-=p&-p;
return res;
} int main(){
n=rd(),m=rd();
rep(i,1,n) a[i]=b[i]=rd();
sort(b+1,b+n+1),cnt=unique(b+1,b+n+1)-b-1;
rep(i,1,n) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
rep(l,1,n) {
memset(s,0,sizeof s);
rep(r,l,n) {
ans[l][r]=ans[l][r-1]+r-l-Que(a[r]);
Add(a[r],1);
}
}
rep(i,1,m) {
int x=rd(),y=rd();
printf("%d\n",ans[x][y]);
}
}

9.Expression

首先要理解题意

所以符号是任意安排顺序,每个符号相当于合并两个数

所以总方案数应该是\((n-1)!\)

转移是也要注意,应该乘上左右两个区间符号交叉出现的价值

将区间\([i,k];[k+1,j]\)合并至\([i,j]\)时要乘上的贡献是

\[\frac{(j-i-1)!}{(k-i)!*(j-k-1)!}
\]

(因为固定了第\(k\)个符号最后,所以是\(j-i-1\))

int n,m;
int a[N],opt[N];
ll g[N][N];
ll fac[N]={1},Inv[N]={1,1}; int main(){
rep(i,1,N-1) fac[i]=fac[i-1]*i%P;
rep(i,2,N-1) Inv[i]=1ll*(P-P/i)*Inv[P%i]%P;
rep(i,1,N-1) Inv[i]=Inv[i]*Inv[i-1]%P;
while(~scanf("%d",&n)) {
rep(i,1,n) a[i]=rd();
rep(i,1,n-1) {
char ch;
do ch=getchar();
while(ch!='+'&&ch!='-'&&ch!='*');
if(ch=='+') opt[i]=1;
else if(ch=='-') opt[i]=2;
else opt[i]=3;
}
memset(g,0,sizeof g);
drep(i,n,1) rep(j,i,n) {
if(i==j) g[i][i]=a[i];//边界条件
rep(k,i,j-1) {
ll t=Inv[k-i]%P*Inv[j-k-1]%P*fac[j-i-1]%P;
if(opt[k]==1) {
g[i][j]=(g[i][j]+(fac[k-i]*g[k+1][j]%P+fac[j-k-1]*g[i][k]%P)*t)%P;
} else if(opt[k]==2) {
g[i][j]=(g[i][j]+(-1ll*fac[k-i]*g[k+1][j]%P+1ll*fac[j-k-1]*g[i][k]%P)*t)%P;
} else {
g[i][j]=(g[i][j]+g[i][k]*g[k+1][j]%P*t)%P;
}
}
}
printf("%lld\n",(g[1][n]%P+P)%P);//可能有负数
}
}

\[\
\]

\[\
\]

10.QSC and Master

众所周知我是一个擅长乱搞的人,所以这个奇怪的题我也是乱搞搞过去的

它长得并不是一个标准的区间dp

两种决策:

直接从左右端点向两边扩展 ;

将这段区间切开

注意由于求得是整个序列的答案所以最后还要合并一下

int n,m;
int a[N],b[N]; ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); }
ll dp[N][N]; int main(){
rep(kase,1,rd()){
n=rd();
rep(i,1,n) a[i]=rd();
rep(i,1,n) b[i]=rd();
memset(dp,-63,sizeof dp);
drep(i,n,1) rep(j,i+1,n) {
if(j-i==1) {
if(gcd(a[i],a[j])!=1) dp[i][j]=b[i]+b[j];
continue;
}
if(gcd(a[i],a[j])!=1) dp[i][j]=max(dp[i][j],dp[i+1][j-1]+b[i]+b[j]);//决策一
rep(k,i,j) dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);//决策二
}
ll ans=0;
rep(i,1,n) {
dp[1][i]=max(dp[1][i],0ll);
rep(j,1,i) dp[1][i]=max(dp[1][i],max(0ll,dp[1][j])+max(0ll,dp[j+1][i]));
}//合并答案
rep(i,1,n) rep(j,i,n) ans=max(ans,dp[i][j]);
printf("%lld\n",ans);
}
}

\[\
\]

\[\
\]

11.Kirinriki

跑错的尺取

const int N=5100,P=1e9+7;

int n,m;
char s[N];
int dp[N]; int main(){
rep(kase,1,rd()){
m=rd();
scanf("%s",s+1);n=strlen(s+1);
int ans=0;
rep(i,3,n*2-1) {
reg int cnt=0,p=1;
drep(j,i/2-(!(i&1)),1) {
if(i-j>n) break;
cnt++;
dp[cnt]=dp[cnt-1]+abs(s[j]-s[i-j]);
while(dp[cnt]-dp[p-1]>m) p++;
ans=max(ans,cnt-p+1);
}
}
printf("%d\n",ans);
}
}

\[\
\]

\[\
\]

12.Zuma

这个题没有素质!它卡常!

\(dp[i][j][0...4]\)表示

0:消完了

1:还剩1个0

2:还剩2个0

3:还剩1个1

4:还剩2个1

转移极其繁琐

卡常技巧:相邻相同的可以压成一个块

(希望我没有想错吧)

const int N=410;
#define chk(a,b) (a>b&&(a=b))//卡常
int n,m;
char s[N];
int a[N],b[N],c[N],dp[N][N][5];
//0 --> 0
//1 --> one 0
//2 --> two 0
//3 --> one 1
//4 --> two 1
int main(){
int T; scanf("%d",&T);
rep(kase,1,T){
scanf("%s",s+1);
n=strlen(s+1);
rep(i,1,n) a[i]=s[i]^'0';
int _n=0;
rep(i,1,n) if(i==1||a[i]!=a[i-1]) {
_n++;
b[_n]=1; c[_n]=a[i];
} else b[_n]++,b[_n]=b[_n];//块合并
n=_n;
rep(i,1,n) rep(j,1,n) rep(o,0,4) dp[i][j][o]=1e9;
rep(i,1,n) {
dp[i][i][c[i]*2+b[i]]=0;
dp[i][i][0]=3-b[i];
}//边界条件初始化
drep(i,n,1) rep(j,i+1,n) {
rep(k,i,j-1){
reg int *x=dp[i][k],*y=dp[k+1][j];//指针卡常
chk(dp[i][j][0],x[0]+y[0]);
chk(dp[i][j][0],x[1]+y[2]);
chk(dp[i][j][0],x[2]+y[2]);
chk(dp[i][j][0],x[2]+y[1]);
chk(dp[i][j][0],x[3]+y[4]);
chk(dp[i][j][0],x[4]+y[3]);
chk(dp[i][j][0],x[4]+y[4]); chk(dp[i][j][1],x[0]+y[1]);
chk(dp[i][j][1],x[1]+y[0]);
chk(dp[i][j][2],x[1]+y[1]);
chk(dp[i][j][2],x[0]+y[2]);
chk(dp[i][j][2],x[2]+y[0]); chk(dp[i][j][3],x[0]+y[3]);
chk(dp[i][j][3],x[3]+y[0]);
chk(dp[i][j][4],x[3]+y[3]);
chk(dp[i][j][4],x[0]+y[4]);
chk(dp[i][j][4],x[4]+y[0]);
}
chk(dp[i][j][0],dp[i][j][1]+2);
chk(dp[i][j][0],dp[i][j][2]+1);
chk(dp[i][j][0],dp[i][j][3]+2);
chk(dp[i][j][0],dp[i][j][4]+1);
}
printf("Case #%d: %d\n",kase,dp[1][n][0]);
}
}

(题解写到一半突然dalao来质问我,发现这种做法好像是错的。。。,但还不清楚是不是)

如果发现有错误请写评论

区间dp专题练习的更多相关文章

  1. 区间dp专题

    HDU4283You Are the One区间dp, 记忆话搜索运行时间:   #include <iostream> #include <cstdio> #include ...

  2. kuangbin专题十二 POJ3186 Treats for the Cows (区间dp)

    Treats for the Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7949   Accepted: 42 ...

  3. 「kuangbin带你飞」专题二十二 区间DP

    layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...

  4. [kuangbin带你飞]专题二十二 区间DP

            ID Origin Title   17 / 60 Problem A ZOJ 3537 Cake   54 / 105 Problem B LightOJ 1422 Hallowee ...

  5. 专题训练之区间DP

    例题:以下例题部分的内容来自https://blog.csdn.net/my_sunshine26/article/details/77141398 一.石子合并问题 1.(NYOJ737)http: ...

  6. UESTC 2015dp专题 A 男神的礼物 区间dp

    男神的礼物 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/contest/show/65 Descri ...

  7. 【专题】区间dp

    1.[nyoj737]石子合并 传送门:点击打开链接 描述    有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这 ...

  8. P1040 加分二叉树 区间dp

    题目描述 设一个nn个节点的二叉树tree的中序遍历为(1,2,3,…,n1,2,3,…,n),其中数字1,2,3,…,n1,2,3,…,n为节点编号.每个节点都有一个分数(均为正整数),记第ii个节 ...

  9. dp专题训练

    ****************************************************************************************** 动态规划 专题训练 ...

随机推荐

  1. 配置kubectl在Mac(本地)远程连接Kubernetes集群

    集群部署在云服务器的ECS上,但是有时需要本地原创连接集群,这就需要通过ApiServer的外网地址去访问集群,但是-/.kube/config下的地址又都是内网,所以可以使用如下方式解决: Mac安 ...

  2. MySQL之SQL演练(四)

    一:准备数据 1.创建数据表 -- 创建 "京东" 数据库 create database jing_dong charset=utf8; -- 使用 "京东" ...

  3. Beego 学习笔记9:Boostrap使用介绍

    BootStrap布局 1>     下载地址: http://v3.bootcss.com/getting-started/#download 根据自己的需要,下载不同的版本.我这里使用的是1 ...

  4. powershell 远程下载并执行

    远程下载文件到本地并执行cmd.exe /c powershell.exe -ExecutionPolicy bypass -noprofile -windowstyle hidden (new-ob ...

  5. const关键字总结

    在C语言中 const是C语言中总结 1.修饰的变量,使其具有常属性,使变量的值不能直接被改变.但是可以通过指针来间接的修改变量的值. 2.便于进行类型检查(在编译时进行类型检查),使编译对处理内容有 ...

  6. 没有用到React,为什么我需要import引入React?

    没有用到React,为什么我需要import引入React? 本质上来说JSX是React.createElement(component, props, ...children)方法的语法糖. 所以 ...

  7. FFmpeg Windows下安装与测试

    FFmpeg 简介 FFmpeg的名称来自MPEG视频编码标准,前面的"FF"代表"Fast Forward",FFmpeg是一套可以用来记录.转换数字音频.视 ...

  8. springboot 单元测试 指定启动类

    问题 在做单元测试时,写了一个工具类,用于注入spring的上下文. public class AppBeanUtil implements ApplicationContextAware { pri ...

  9. httprunner学习7-extract提取content返回对象

    前言 提取response返回的对象数据,用extract关键字.前面有关于token的取值,通过content.token取值. 本篇详细讲解如何从返回的json数据提取出想要的各种数据 conte ...

  10. Windows server服务器入侵检查

    基本检查点   检测不正常账户 查找被新增的账号,特别是管理员群组的(Administrators group)里的新增账户. C:\lusrmgr.msc C:\>net localgroup ...