「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 ...
随机推荐
- 记录我个人对Telegram的了解
对Telegram(电报) 开始的了解是以为提供了Telegram API,就可以基于它进行开发自己的即时通讯(Instant Messaging)程序. 大概使用过: webogram 和 tele ...
- getElementsBy 系列方法相比querySelector系列的区别
最近在做的项目中,使用querySelectorAll获取了同class名的元素后,绑定onmouseover事件和onmouseout后,多次在几个元素上移入移出操作时,控制台出现了报错的问题,最后 ...
- hbase-2.0.4集群部署
hbase-2.0.4集群部署 1. 集群节点规划: rzx1 HMaster,HRegionServer rzx2 HRegionServer rzx3 HRegionServer 前提:搭建好ha ...
- 管理员技术(五): 配置文档的访问权限、 配置附加权限、绑定到LDAP验证服务、配置LDAP家目录漫游
一.配置文档的访问权限 问题: 本例要求将文件 /etc/fstab 拷贝为 /var/tmp/fstab,并调整文件 /var/tmp/fstab的权限,满足以下要求: 1> 此文件的拥有者 ...
- 用javascript插入<style>样式
function addCSS(cssText){ var style = document.createElement('style'), //创建一个style元素 head = document ...
- js设计模式——8.中介者模式
js设计模式——8.中介者模式 /*js设计模式——中介者模式*/ class A { constructor() { this.number = 0; } setNumber(num, m) { t ...
- js实现超简单sku组合算法
let arr = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], ]; function cartesianProductOf() { return ...
- docker包含哪些内容(1)
包含哪些内容? 如下图,三大块: 下面分别介绍各部分包含的内容. 启程 “启程”会介绍容器的生态系统,让大家先从整体上了解容器都包含那些技术,各种技术之间的相互关系是什么,然后再来看我们的教程都会涉及 ...
- 如何在普通用户权限cmd怎么使用命令行变为管理员权限
这两天在弄MySql,由于我下载的是免安装版本,环境自己配置了一下.有强迫症不喜欢某些服务打开在我不需要的时候,我一般都设置为手动,但是每次使用数据库时都要使用net start mysql启动MyS ...
- hexo的next主题博客中加入分类页面的js,实现多级目录,并且能够点击展开,隐藏下级目录~(不知道算不算深度优化~~~)
个人博客:https://mmmmmm.me 源码:https://github.com/dataiyangu/dataiyangu.github.io 多级标题 在自己的xxxx.md文件中做如下修 ...