「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 ...
随机推荐
- CF817E Choosing The Commander
\(\mathtt{CF817E}\) \(\mathcal{Description}\) 有 \(q\) 个操作\((1 \leq q \leq 10^{5})\): 1.加入一个数 \(p_i(1 ...
- TCP协议解析及相关问题
TCP协议是什么: TCP是一种传输控制层的协议(TCP,Transmission Control Protocol)是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议.也就是要 ...
- python 调用redis
#!/usr/bin/env python #_*_ coding:UTF-8 _*_ import redis import pickle #普通连接 ''' db="db1" ...
- c#委托(Delegates)--基本概念及使用 转发
在我这菜鸟理解上,委托就是可以用方法名调用另一方法的便捷方法,可以简化switch等语句的重复.最近做项目的时候恰好需要用到委托,便来复习及学习委托的使用.嗯...本人以前并没有用过,只是稍微知道而已 ...
- 解决Office 2010 每次打开word时出现配置进度框
来自百度经验 装好Office 2010后,每次打开都会出现配置进度框,很烦人,怎么办呢 确认你的10版Office已激活,激活状态如图(激活工具一般在你下载的安装包里都有) 直接在”开始“运行框里输 ...
- 绿盟-WEB应用漏洞扫描系统
************************************************** WEB应用漏洞扫描系统 一.工具的介绍与使用 ************************** ...
- 用EditText控件的属性inputType
android:inputType参数类型说明 android:inputType="none"--输入普通字符 android:inputType="text" ...
- linux内核编译时如何根据spec指定编译包
问题: 1> rpmbuild -bb SPECS/kernel.spec --define="_topdir `pwd`" 编译 出的包并未包含kernel-firmwar ...
- Handler Looper源码解析(Android消息传递机制)
Android的Handler类应该是常用到的,多用于线程间的通信,以及子线程发送消息通知UI线程刷新View等等.这里我主要总结下我对整个消息传递机制,包括Handler,Looper,Messag ...
- ArrayList、Vector、LinkedList的区别
ArrayList.Vector.LinkedList的区别 1.底层数据结构: ArrayList底层实现是动态数组 Vector底层实现是动态数组 LinkedList底层实现是双链表 2.扩容 ...