「THUSC 2016」成绩单 & 方块消除 (区间dp)
$f[l][r][mi][mx]$表示从l到r发到还没发的部分的最小值为mi最大值为mx时的最小代价。
$f[l][r][0][0]$表示从l到r全部发完的代价。
自己写的无脑dp,枚举中转点k,分成(i,k) (k+1,j)两个区间,分别用mi,mx都在左区间,都在右区间,一个左一个右来转移,这样会发现可以转移过来的都是某个一维或者二维前缀和的形式,于是我开了四个二维数组,暴力维护了6个前缀和更新答案。。。
然后代码就比较鬼畜
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#define Formylove return 0
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=;
typedef long long LL;
typedef double db;
using namespace std;
int n,sz,w[N],ls[N];
LL a,b,f[N][N][N][N]; template<typename T>void read(T &x) {
char ch=getchar(); x=; T f=;
while(ch!='-'&&(ch<''||ch>'')) ch=getchar();
if(ch=='-') f=-,ch=getchar();
for(;ch>=''&&ch<='';ch=getchar()) x=x*+ch-''; x*=f;
} LL pf(LL x) { return x*x; }
void pre() {
sort(ls+,ls+n+);
sz=unique(ls+,ls+n+)-(ls+);
For(i,,n) w[i]=lower_bound(ls+,ls+sz+,w[i])-ls;
memset(f,/,sizeof(f));
For(i,,n) {
int mi=w[i],mx=w[i];
For(j,i,n) {
mi=min(mi,w[j]);
mx=max(mx,w[j]);
f[i][j][mi][mx]=;
f[i][j][][]=a+b*pf(ls[mx]-ls[mi]);
}
}
} LL p1[N][N],p2[N][N],p3[N][N],p4[N][N],p5,p6;
void clear() {
memset(p1,/,sizeof(p1));
memset(p2,/,sizeof(p2));
memset(p3,/,sizeof(p3));
memset(p4,/,sizeof(p4));
} void get_min(LL &x,LL y) { if(y<x) x=y; } void solve() {
For(len,,n) For(i,,n-len+) {
int j=i+len-;
For(k,i,j-) {
clear();
Rep(mi,sz,) {
p5=p6=1e18;
For(mx,mi,sz) {
p5=min(p5,f[i][k][mi][mx]);
p2[mi][mx]=min(p2[mi][mx],p5);
p6=min(p6,f[k+][j][mi][mx]);
p1[mi][mx]=min(p1[mi+][mx],p6);
p3[mi][mx]=min(p3[mi+][mx],f[k+][j][mi][mx]);
p4[mi][mx]=min(p4[mi+][mx],f[i][k][mi][mx]); get_min(f[i][j][mi][mx],f[i][k][mi][mx]+f[k+][j][][]);
get_min(f[i][j][mi][mx],f[i][k][][]+f[k+][j][mi][mx]); get_min(f[i][j][mi][mx],f[i][k][mi][mx]+p1[mi][mx]);
get_min(f[i][j][mi][mx],p2[mi][mx]+f[k+][j][mi][mx]);
get_min(f[i][j][mi][mx],p5+p3[mi][mx]);
get_min(f[i][j][mi][mx],p4[mi][mx]+p6);
get_min(f[i][j][][],f[i][j][mi][mx]+a+b*pf(ls[mx]-ls[mi]));
}
}
get_min(f[i][j][][],f[i][k][][]+f[k+][j][][]);
}
}
printf("%lld\n",f[][n][][]);
} int main() {
#ifdef ANS
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
read(n);
read(a); read(b);
For(i,,n) read(w[i]),ls[i]=w[i];
pre();
solve();
Formylove;
}
正解的转移非常简单,写出这种转移的人大概和我这种zz之间有着几个世纪的代沟。。。
一开始我的代码wa了才找了个正解来抄,结果还是wa了,最后发现是离散写错了。。。lower_bound里面sz写成了n。。
这里$f[l][r][mi][mx]$应该是从l到r,r一定还没发的最小代价,具体还是看代码吧,感性理解一下
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#define Formylove return 0
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=;
typedef long long LL;
typedef double db;
using namespace std;
int n,sz,w[N],ls[N];
LL a,b,f[N][N][N][N]; template<typename T>void read(T &x) {
char ch=getchar(); x=; T f=;
while(ch!='-'&&(ch<''||ch>'')) ch=getchar();
if(ch=='-') f=-,ch=getchar();
for(;ch>=''&&ch<='';ch=getchar()) x=x*+ch-''; x*=f;
} LL pf(LL x) { return x*x; }
void pre() {
sort(ls+,ls+n+);
sz=unique(ls+,ls+n+)-(ls+);
For(i,,n) w[i]=lower_bound(ls+,ls+sz+,w[i])-ls;
memset(f,/,sizeof(f));
For(i,,n) {
int mi=w[i],mx=w[i];
For(j,i,n) {
mi=min(mi,w[j]);
mx=max(mx,w[j]);
f[i][j][mi][mx]=;
f[i][j][][]=a+b*pf(ls[mx]-ls[mi]);
}
}
} void get_min(LL &x,LL y) { if(y<x) x=y; } void solve() {
For(len,,n) For(i,,n-len+) {
int j=i+len-;
f[i][j][w[j]][w[j]]=f[i][j-][][];
For(k,i,j-) For(mi,,sz) For(mx,mi,sz)
get_min(f[i][j][min(mi,w[j])][max(mx,w[j])],f[i][k][mi][mx]+(k+<=j-?f[k+][j-][][]:));
For(k,i,j) For(mi,,sz) For(mx,mi,sz)
get_min(f[i][j][][],f[i][k][mi][mx]+a+b*pf(ls[mx]-ls[mi])+(k+<=j?f[k+][j][][]:));
}
printf("%lld\n",f[][n][][]);
} int main() {
#ifdef ANS
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
read(n);
read(a); read(b);
For(i,,n) read(w[i]),ls[i]=w[i];
pre();
//For(i,1,n) printf("%d ",w[i]);
solve();
Formylove;
}
应该算是上一道题的简化版。有了上一次的正解的转移这个就很好写了。思路差不多。$f[l][r][k]$(仅在$a[l]=a[r]$时有意义)表示l和r还没消除,从l到r包括l,r一共有k个和l,r同色的方块还没消除,其他的都消除完了的最大价值。g[l][r]表示l到r全部消除的最大价值。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#define Formylove return 0
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=;
typedef long long LL;
typedef double db;
using namespace std;
int T,n,a[N],f[N][N][N],g[N][N]; template<typename T>void read(T &x) {
char ch=getchar(); x=; T f=;
while(ch!='-'&&(ch<''||ch>'')) ch=getchar();
if(ch=='-') f=-,ch=getchar();
for(;ch>=''&&ch<='';ch=getchar()) x=x*+ch-''; x*=f;
} int main() {
#ifdef ANS
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
read(T);
For(cs,,T) {
memset(f,,sizeof(f));
memset(g,,sizeof(g));
read(n);
For(i,,n) read(a[i]);
For(i,,n) g[i][i]=,f[i][i][]=;
For(len,,n) For(i,,n-len+) {
int j=i+len-;
if(a[i]==a[j]) {
For(k,i,j-) if(a[k]==a[j]) {
For(l,,k-i+) if(f[i][k][l]>=) {
f[i][j][l+]=max(f[i][j][l+],f[i][k][l]+(k+<=j-?g[k+][j-]:));
}
}
For(l,,j-i+)
g[i][j]=max(g[i][j],f[i][j][l]+l*l);
}
For(k,i,j-)
g[i][j]=max(g[i][j],g[i][k]+g[k+][j]);
}
printf("Case %d: %d\n",cs,g[][n]);
}
Formylove;
}
之前还以为自己dp学的还可以,现在看来还是太肤浅了
「THUSC 2016」成绩单 & 方块消除 (区间dp)的更多相关文章
- loj 2292「THUSC 2016」成绩单
loj 看着就很区间dp,所以考虑求\(f_{i,j}\)表示区间\([i,j]\)的答案.注意到贡献答案的方式是每次选一个连续段,拿走后剩下的段拼起来继续段,所以转移就考虑从最后一次选的方法转移过来 ...
- 【题解】【THUSC 2016】成绩单 LOJ 2292 区间dp
Prelude 快THUWC了,所以补一下以前的题. 真的是一道神题啊,网上的题解没几篇,而且还都看不懂,我做了一天才做出来. 传送到LOJ:(>人<:) Solution 直接切入正题. ...
- LOJ 2292 「THUSC 2016」成绩单——区间DP
题目:https://loj.ac/problem/2292 直接 DP 很难做,主要是有那种 “一个区间内部有很多个别的区间” 的情况. 自己想了一番枚举 max-min 的最大限制,然后在该基础上 ...
- 2018.10.27 loj#2292. 「THUSC 2016」成绩单(区间dp)
传送门 g[i][j][k][l]g[i][j][k][l]g[i][j][k][l]表示将区间l,rl,rl,r变成最小值等于kkk,最大值等于lll时的花费的最优值. f[i][j]f[i][j] ...
- 【LOJ】#2292. 「THUSC 2016」成绩单
题解 神仙dp啊><(也有可能是我菜) 我们发现,想要拿一段区间的话,只和这个区间的最大值和最小值有关系,那么我们考虑,如果一个区间[l,r]我们拿走了一些数后,使它的最小值是a,最大值是 ...
- loj2292 「THUSC 2016」成绩单
ref 我是傻逼,我啥也不会,这是我抄的. #include <iostream> #include <cstring> #include <cstdio> usi ...
- LOJ 2991 「THUSC 2016」补退选——trie+线段树合并或vector
题目:https://loj.ac/problem/2291 想了线段树合并的做法.就是用线段树维护 trie 的每个点在各种时间的操作. 然后线段树合并一番,线段树维护前缀最大值,就是维护最大子段和 ...
- 【LOJ】#2291. 「THUSC 2016」补退选
题解 在trie树上开vector记录一下这个前缀出现次数第一次达到某个值的下标,以及记录一下现在这个前缀有多少个 为什么thusc有那么水的题--是为了防我这种cai ji爆零么= = 代码 #in ...
- loj2291 「THUSC 2016」补退选
ref pkusc 快到了,做点 thusc 的题涨涨 rp-- #include <iostream> #include <cstring> #include <cst ...
随机推荐
- jsp service bean
//在jsp中使用后台service中方法需要在jsp页面引入service bean 1 <%@page import="com..entity.Users"%> & ...
- python3-xlwt-Excel设置(字体大小、颜色、对齐方式、换行、合并单元格、边框、背景、下划线、斜体、加粗)
搬运出处: https://blog.csdn.net/weixin_44065501/article/details/88899257 # coding:utf-8 import patterns ...
- Windows 屏幕保护程序
{ 创建一个win32 窗口项目,不是控制台的 把exe改为src文件 复制到windows目录下 ok }
- IntelliJ IDEA下载地址
http://www.jetbrains.org/display/IJOS/Download
- XSS的原理分析与解剖:第四章(编码与绕过)*******************未看**********************
0×01前言 很抱歉,这第四章被我推了几个月,今天是元旦难得有空,就把第四章写下.我先把主要使用的编码说下,介绍完会说下绕过. 本文建议与<杂谈如何绕过WAF>一同阅读. 0×02 URL ...
- c go数据类型对应关系
DataType C cgo sizeof--------------------+--------------------+------------------------------------- ...
- window安装reidis完成之后,想要把数据存入redis,必须开扩展,不然报错,redis windows phpstudy 安装扩展
redis windows phpstudy 安装扩展 1.http://windows.php.net/downloads/pecl/releases/redis/3.1.5rc1/ 2.htt ...
- json path espressions的语法学习
json path espressions的语法学习 $:跟对象\元素 @:当前对象\元素 ?():应用过滤器(脚本)表达式 如: { "store": { "bo ...
- php5模块pdo、pdo_mysql、mysqli的添加
一.环境LAMP都是源码安装,PHP安装的时候没有配置pdo_mysql和mysqli,pdo是php5默认带的.PHP5的源码都在,只需要把php5的模块功能扩展就可以了. php源码目录:/usr ...
- TLS/SSL 协议 - ServerKeyExchange、ServerHelloDone
ServerKeyExchange ServerKeyExchange消息的目的是携带密钥交换的额外数据.消息内容对于不同的协商算法套件都会存在差异.在某些场景中,服务器不需要发送任何内容,这意味着在 ...