「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 ...
随机推荐
- JavaIO流之字节流
什么是字节? 所谓字节(Byte),是计算机数据存储的一种计量单位.一个二进制位称为比特(bit),8个比特组成一个字节,也就是说一个字节可以用于区分256个整数(0~255).由此我们可以知道,字节 ...
- js实现复制|剪切指定内容到粘贴板--clipboard
这是著名开源项目 clipboard.js 的 README.md,里面讲解的更加详细,有兴趣的同学可以了解一下.项目地址:https://github.com/zenorocha/clipboard ...
- rabbitmq使用延迟时报异常
声明交换机为延迟时报异常( unknown exchange type 'x-delayed-message')的解决方法 服务端需下载安装插件: 1.下载插件包 2.将下载后的插件包移至服务安装目录 ...
- Oracle - 单表查询相关
-- 单表查询 -- 查询表的所有数据, *代表所有 -- select * from [表名]; -- 查询表中指定字段的值 -- select [字段1], [字段2] ... from [表名] ...
- Dataphin支持哪些数据源
业务数据存储是业务系统最基本的构成,构建数据中台,就是要将这些数据集中起来放到一个有更强算力的地方集中处理,所以对于数据集成的能力是构建数据中台最基本要求: 从存储的发展历程来看,由于不同的业务场景需 ...
- vue2 开发环境部署 及 打包配置
一.脚手架工具(vue2 的脚手架工具是 vue-cli) 1.脚手架工具的安装 参考 : https://blog.csdn.net/wulala_hei/article/details/804 ...
- JAVA中 成员变量和和实例变量区别
java语言支持的变量类型 类变量:独立于方法之外的变量,用 static 修饰. 局部变量:类的方法中的变量. 实例变量(全局变量):独立于方法之外的变量,不过没有 static 修饰. publi ...
- makefile.new(7117) : error U1087: cannot have : and :: dependents for same target
makefile.new(7117) : fatal error U1087: cannot have : and :: dependents for same target(2012-05-21 2 ...
- CSS:CSS 链接
ylbtech-CSS:CSS 链接 1.返回顶部 1. CSS 链接 不同的链接可以有不同的样式. 链接样式 链接的样式,可以用任何CSS属性(如颜色,字体,背景等). 特别的链接,可以有不同的样式 ...
- 使用linkedhashmap实现LRU(最近最少使用缓存算法)
import java.util.LinkedHashMap; import java.util.Map; public class LRUCache<K, V> extends Link ...