博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【CF321E】+【bzoj5311】贞鱼
阅读量:4652 次
发布时间:2019-06-09

本文共 2260 字,大约阅读时间需要 7 分钟。

决策单调性 + WQS二分

我们首先列出转移式: \(f[i]=Min(f[j]+Sum[j+1 , i])\)

首先我们考虑如果让一段区间的小鱼在一起的代价怎么预处理,我们可以对于一个上三角矩阵求个二维前缀和,那么我们计算 \([j+1,i]\) 这段区间的代价就是 \(S[i,i]-S[i,j]\) ,得到的是一个等腰直角三角形的和

那么原来的转移式就可以这么写:\(f[i]=Min(f[j]+S[i,i]-S[i,j])\)

然后我们不考虑车辆数量的限制,那么对于 j 和 k ,如果 \(j<k\) ,那么首先 \(f[j]\) 必然小于 \(f[k]\) ,但是随着 i 的增大, \(S[i,i]\) 是不变的,但是 \(S[i,j]\)\(S[i,k]\) 之间的差肯定是越来越大的,即对于 \(f[j]-S[i,j]\)\(f[k]-S[i,k]\) ,肯定是一开始选 j 比较优,后来两个函数有一个交点,过了这个交点就是 k 比较优了,并且两个函数的交点只有一个,所以我们可以二分一个交点,然后保持交点和 j 同时单调递增,这样就可以做一个 O(n) 的斜率优化 dp 了...

但问题是这 goushi 的车辆是有数量限制的,但是我们发现总价格和使用车辆数是负相关的,那么我们可以考虑对于每辆车加上一个租赁代价,这在斜率优化中是不影响计算的,然后租赁的代价越高,最优解中使用车辆数肯定越小,那么我们可以二分这个租赁代价,得到车辆数恰好为指定的 K 时,把租赁的代价减去,这样就得到了答案

总复杂度讲道理是 \(O(n~log n ~ log ~S[n,n])\) ,因为外面 wqs 二分 \(S[n,n]\),里面也要二分交点

code

//by Judge#pragma GCC optimize("Ofast")#include
#define Rg register#define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i
I;--i)#define ll long longusing namespace std;const int M=4003;#ifndef Judge#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)#endifchar buf[1<<21],*p1=buf,*p2=buf;inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;} int n,K,ans,s[M][M],f[M],w[M];inline int calc(int j,int i){ return f[j]+s[i][i]-s[j][i];}inline bool judge(int j,int k,int i){ //判断 f[i] 大小 int valj=calc(j,i),valk=calc(k,i); if(valj^valk) return valj>valk; return w[j]>=w[k];}inline int rate(int j,int k){ //得到交点位置 int l=k+1,r=n; while(l<=r){ int mid=(l+r)>>1; if(judge(j,k,mid)) r=mid-1; else l=mid+1; } return l;}inline bool check(int mid){ //二分附加权值 static int head,tail,q[M]; q[head=tail=1]=0; fp(i,1,n){ //斜率优化 while(head
rate(q[tail],i)) --tail; q[++tail]=i; } return w[n]<=K;}int main(){ n=read(),K=read(); fp(i,1,n) fp(j,1,n) s[i][j]=read(); fp(i,1,n) fp(j,1,i) s[i][j]=0; fp(i,1,n) fp(j,1,n) s[i][j]=s[i][j-1]+s[i][j]; fp(i,1,n) fp(j,1,n) s[i][j]=s[i-1][j]+s[i][j]; int l=0,r=s[n][n]; while(l<=r){ int mid=(l+r)>>1; if(check(mid)) r=mid-1,ans=f[n]-K*mid; else l=mid+1; } return !printf("%d\n",ans);}

转载于:https://www.cnblogs.com/Judge/p/11311660.html

你可能感兴趣的文章
AFore.NET 翻译
查看>>
[大牛翻译系列]Hadoop(8)MapReduce 性能调优:性能测量(Measuring)
查看>>
What to do when the Chinese Characters are messed up when extracting from zip archive?
查看>>
SQLYog快捷键大全
查看>>
(转载)DLL动态链接库编程入门之三:MFC规则DLL(上)
查看>>
隐藏Nginx或Apache以及PHP的版本号的方法
查看>>
N32926之jlink调试配置
查看>>
ASP.NET ACCESS 分页
查看>>
HashMap
查看>>
Android广播机制概述
查看>>
mysql触发器
查看>>
我是怎么让全国最大的儿童失踪预警平台流量掉底的
查看>>
领扣(LeetCode)二叉树的中序遍历 个人题解
查看>>
MySQL5.5登录密码忘记了,怎嘛办?
查看>>
[javascript]9宫格拖拽拼图游戏 puzzle
查看>>
论文笔记《Hand Gesture Recognition with 3D Convolutional Neural Networks》
查看>>
java内部类
查看>>
Entity Framework底层操作封装(3)
查看>>
python 全栈开发,Day37(操作系统的发展史)
查看>>
InputStream 转换 InputStreamReader再转换BufferedReader
查看>>