【Codeforces 321E / BZOJ 5311】【DP凸优化】【单调队列】贞鱼
题意:
有n条超级大佬贞鱼站成一行,现在你需要使用恰好k辆车把它们全都运走。要求每辆车上的贞鱼在序列中都是连续的。每辆车上的贞鱼会产生互相怨恨的值,设a与b之间的怨恨值为G(a,b),一辆车上的贞鱼的编号从L到R,那么这辆车上的怨恨值为\(\sum_{L<=a,b<=R}G(a,b)\)。注意G(a,b)=G(b,a),一对贞鱼之间的怨恨值只算一次,也就是G(a,b)和G(b,a)只算一次。
1<=n<=4000,1<=k<=min(n,800),0<=G(a,b)<=10
输入格式
第一行两个整数n,k;
接下来是一个n*n的矩阵表示G[][],其中G(i,i)=0.且保证矩阵是对称的。
输出格式
一个整数ans表示怨恨值值之和的最小值。
思路:
DP凸优化的部分
首先,恰好使用k辆车这个限制非常的迷,不禁使我们想到了一个算法:DP凸优化。(要是平时拿给我做,我绝对想不到这玩意)至于什么是DP凸优化,这里就先行跳过讲解了,可以在关于WQS二分算法以及其一个细节证明-by Creeper_LKF里学习一下。
至于这道题,我们发现可以直接二分增加一辆车需要额外增加的代价,就可以限制车的数量。(代价越大,多使用一辆车就可能比较亏,还不如在一辆车里多塞几条贞鱼)。
然后就可以在二分出来的额外代价的意义下跑一个\(O(n^2)\)的dp了,总时间为\(O(n^2\log n)\),要被卡。
单调队列转移的部分
下面考虑如何优化。
首先还是看一下n*n的转移式是怎样的:
\]
其中dp[i]表示当前以第i条贞鱼为最后一辆车的最后一条鱼的最小值。然后sum[i][j]为给出的矩阵的前缀和。你会发现后面那一坨就是矩阵中(j+1,j+1)到(i,i)的和,也就是从j+1到i这些贞鱼互相怨恨的值的总和。但是由于题目的要求,还要除以2。
优化的话,仔细观察一波之后可以发现这玩意的转移时具有单调性的(前提是你dp的定义一定要是对的)。
选择单调性的话,是和dp值的增长率的大小有关的。如果不懂的话,可以看一下下面这个图。
首先将式子中的对于i而言的非常数项提出来:-(sum[i][j]+sum[j][i]-sum[j][j]),然后下面的图表现的是括号里面(先令作F(i,j))的几何意义。
j1<j2是显然的.其中橙色部分v表示的就是F(i,j2)随i的变化量,而绿色部分就是F(i,j1)随i的变化量。可见delta(F(i,j2))是大于delta(F(i,j1))的,也就是说dp是中和sum[][]有关的那一坨中中,如果j1<j2,因为对于j1和j2而言,sum[i][i]的增加率肯定是相等的,而F(i,j1)增加的要慢一些,也就是它阻碍sum[i][i]增加的作用要小一些,那么对应的j1的总的增加量就要大一些。
因为我们要求的是最小值,而此时如果dp[j1]还大于dp[j2]的话,在i增大的过程中,j1是绝对不可能成为决策点的。于是就可以把j1舍去了。
这里博主可能说的有些复杂,能理解就好。
这样子就可以利用决策单调性把整体时间复杂度优化到\(O(n\log n\log maxval)\)了。
至于决策单调性的具体过程,大概就是先发现一个决策点对一个连续的区间进行转移,所以可以在队列里面放入一个决策点当前能够更新的左右端点和自己的下标。
首先先默认能够更新到n,然后在之后的插入决策点的过程中,将绝对不可能进行之后的转移的点弹掉,然后在一个完整的区间内部进行二分,将这个区间拆成两个,其中右边的那个就是新插进去的决策点的更新区间啦。(具体参见代码)
坑点
1.转移式一定要记得/2
2.DP凸优化的时候,注意外层二分的写法,最好是自己调一下。
3.在最后算答案加回多算的代价的时候,记得是每辆车多算的代价乘上k,而不是乘上你这个方案的车的数量
4.在DP的转移过程中,除了要将值的大小设为第一比较关键字外,还要将选取车的数量设为第二关键字进行比较。通常是这样的:如果你在外层的二分中是判定当前选取车的数量<= k的时候算答案的话,你在内层就要保证在dp值相同的情况下,尽可能地少使用车;反之亦然(全部反过来就行了)。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cctype>
#define MAXN 4000
#define MAXK 800
#define INF 0x7FFFFFFF
using namespace std;
struct node
{
int l,r,j;
node(){};
node(int _l,int _r,int _j):l(_l),r(_r),j(_j){};
};
int n,dp[MAXN+5],dpnum[MAXN+5],sum[MAXN+5][MAXN+5];
int k;
node que[MAXN+5];
int Get(int j,int i)
{
return dp[j]+(sum[i][i]-sum[i][j]-sum[j][i]+sum[j][j])/2;//记得除以2
}
int Cmp(int v1,int v2,int num1,int num2)//专门用来进行双关键字比较的函数
{
if(v1<v2)
return 1;
else if(v1>v2)
return -1;
else if(num1>num2)
return -1;
else if(num1<num2)
return 1;
return 0;
}
int Check(int x)
{
int s=0,t=0;
que[t++]=node(1,n,0);
dp[0]=0;
for(int i=1;i<=n;i++)
{
while(s<t&&que[s].r<i)
s++;//先判定当前i是否在转移的区间内,否则就舍去,因为以后也用不上了。
int j=que[s].j;
dpnum[i]=dpnum[j]+1;
dp[i]=dp[j]+(sum[i][i]-sum[i][j]-sum[j][i]+sum[j][j])/2+x;
while(s<t&&Cmp(Get(que[t-1].j,que[t-1].l),Get(i,que[t-1].l),dpnum[que[t-1].j],dpnum[i])==-1)
t--;//直接和左端点进行贡献大小的比较,如果更优的话直接就舍去了。
if(s<t)//找一个无法完全取代的决策点
{
int L=que[t-1].l-1,R=que[t-1].r+1;
while(L+1<R)//二分确定这个决策点到底从哪里断开
{
int mid=(L+R)/2;
if(Cmp(Get(i,mid),Get(que[t-1].j,mid),dpnum[i],dpnum[que[t-1].j])==1)
R=mid;
else
L=mid;
}
que[t-1].r=L;
if(R<=n)
que[t++]=node(R,n,i);//不能加入非法区间
}
else
que[t++]=node(i,n,i);//空的就直接加进去
}
return dpnum[n];
}
const int MAXSIZE=1<<15;//网上粘的读入优化,还没搞懂咋回事...恶意卡常,加上去就好了
char buf[MAXSIZE],*p1=buf,*p2=buf;
#define gc p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin),p1==p2)?EOF:*p1++
int read()
{
int x=0,f=1;char ch=gc;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc;}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc;}
return x*f;
}
int main()
{
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
sum[i][j]=read();
// scanf("%d",&sum[i][j]);
sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
}
int L=0,R=INF,mid;
while(L<R)
{
mid=(1LL*L+1LL*R)>>1LL;
int ret=Check(mid);
if(ret<=k)
R=mid;//前者
else
L=mid+1;
}
int ret=Check(R);
int val=dp[n]-R*k;//注意是-R*k而不是-R*ret,因为注重的是答案,而不是方案
printf("%d\n",val);
return 0;
}
【Codeforces 321E / BZOJ 5311】【DP凸优化】【单调队列】贞鱼的更多相关文章
- BZOJ.1010.[HNOI2008]玩具装箱toy(DP 斜率优化/单调队列 决策单调性)
题目链接 斜率优化 不说了 网上很多 这的比较详细->Click Here or Here //1700kb 60ms #include<cstdio> #include<cc ...
- 「学习笔记」wqs二分/dp凸优化
[学习笔记]wqs二分/DP凸优化 从一个经典问题谈起: 有一个长度为 \(n\) 的序列 \(a\),要求找出恰好 \(k\) 个不相交的连续子序列,使得这 \(k\) 个序列的和最大 \(1 \l ...
- 【题解】Cats Transport (斜率优化+单调队列)
[题解]Cats Transport (斜率优化+单调队列) # When Who Problem Lang Verdict Time Memory 55331572 Jun/09/2019 19:1 ...
- BZOJ 1499 [NOI2005] 瑰丽华尔兹 | 单调队列优化DP
BZOJ 1499 瑰丽华尔兹 | 单调队列优化DP 题意 有一块\(n \times m\)的矩形地面,上面有一些障碍(用'#'表示),其余的是空地(用'.'表示).每时每刻,地面都会向某个方向倾斜 ...
- bzoj 1499 [NOI2005]瑰丽华尔兹——单调队列优化dp
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1499 简单的单调队列优化dp.(然而当时却WA得不行.今天总算填了坑) 注意滚动数组赋初值应 ...
- BZOJ 3126 [USACO2013 Open]Photo (单调队列优化DP)
洛谷传送门 题目大意:给你一个长度为$n$的序列和$m$个区间,每个区间内有且仅有一个1,其它数必须是0,求整个序列中数字1最多的数量 神题,竟然是$DP$ 定义$f_{i}$表示第i位放一个1时,最 ...
- bzoj 3831 Little Bird (单调队列优化dp)
/*先贴个n*n的*/ #include<iostream> #include<cstdio> #include<cstring> #define maxn 100 ...
- bzoj 3126: [Usaco2013 Open]Photo——单调队列优化dp
Description 给你一个n长度的数轴和m个区间,每个区间里有且仅有一个点,问能有多少个点 Input * Line 1: Two integers N and M. * Lines 2..M+ ...
- dp凸优化/wqs二分学习笔记(洛谷4383 [八省联考2018]林克卡特树lct)
qwq 安利一个凸优化讲的比较好的博客 https://www.cnblogs.com/Gloid/p/9433783.html 但是他的暴力部分略微有点问题 qwq 我还是详细的讲一下这个题+这个知 ...
随机推荐
- [Reinforcement Learning] Value Function Approximation
为什么需要值函数近似? 之前我们提到过各种计算值函数的方法,比如对于 MDP 已知的问题可以使用 Bellman 期望方程求得值函数:对于 MDP 未知的情况,可以通过 MC 以及 TD 方法来获得值 ...
- use case 的缺陷
用use case 获取需求的方法是否有什么缺陷,还有什么地方需要改进? 1.故事/人物/场景非常适合交互式的系统,但是对于其他类型的需求(算法,速度,扩展性,安全性,以及和 系统技术相关的 ...
- iTOP-4418开发板支持Android4.4/5.1.1系统、Linux3.4.39、QT2.2/4.7/5.7、Ubuntu12.04
核心板参数 尺寸:50mm*60mm 高度:核心板连接器组合高度1.5mm PCB层数:6层PCB沉金设计 4418 CPU:ARM Cortex-A9 四核 S5P4418处理器 1.4GHz 68 ...
- Windows如何上传代码到Github
1.首先得安装git客户端 进入官网:https://git-scm.com/ ,点击右侧下载windows版本的软件包,然后双击安装就可以了. 安装完成之后,在开始菜单可以看到,此时,在想上传的文件 ...
- Python multiprocessing
 推荐教程 官方文档 multiprocess各个模块较详细介绍 廖雪峰教程--推荐 Pool中apply, apply_async的区别联系 (推荐)python多进程的理解 multiproce ...
- WPF实战之一 桌面消息框(右下角消息弹出框)
此版本是根据别人的项目改造的,记录下笔记 原文:https://blog.csdn.net/catshitone/article/details/75089069 一.即时弹出 1.创建弹出框 新建一 ...
- nginx unit PHP
2018-12-26 14:20:33 星期三 综述: nginx unit php 的关系: nginx -> 转发请求到 8300端口 -> unit 转发 8300 收到的请求 -& ...
- Sprite子节点透明度不能跟随父节点变化的问题求解(转)
原出处忘记了. [已解决]Sprite子节点透明度不能跟随父节点变化的问题求解 自己封装了一个按钮控件,点击的时候封装了一些动作,其中有透明度的变化. 当点击发生的时候,Sprite本体执行正常,但是 ...
- springboot 中页面跳转问题:window.location.href
我的一个HTML页面 点击注册 本该到注册页面,但是却一直跳到同目录的一个Error.html文件夹下 该页面: 删掉Error.html还不行:会报错,而且改变window.location.hre ...
- js数据结构与算法——二叉树
function BinaryTree(){ var Node = function(key){ this.key = key; //值 this.left = null; //左箭头 this.ri ...