[bzoj P2726] [SDOI2012]任务安排

Time Limit: 10 Sec Memory Limit: 128 MB

Submit: 1204 Solved: 349
[Submit][Status][Discuss]
Description

机器上有N个需要处理的任务,它们构成了一个序列。这些任务被标号为1到N,因此序列的排列为1,2,3...N。这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和。注意,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。
Input

第一行两个整数,N,S。
接下来N行每行两个整数,Ti,Fi。
Output

一个整数,为所求的答案。
Sample Input

5 1
1 3
3 2
4 3
2 3
1 4
Sample Output

153

没有数据范围,差评!

自己从discuss里面搞来了:

[1, 4] 0<N<=1000 0<=S<=2^8 0<=Ti<=2^8 0<=Fi<=2^8

[5, 12] 0<N<=300000 0<=S<=2^8 0<=Ti<=2^8 0<=Fi<=2^8

[13, 20] 0<N<=100000 0<=S<=2^8 -(2^8)<=Ti<=2^80<=Fi<=2^8

看这数据范围。。

刚开始还没有想到???吃枣药丸

这题如果我们正推需要二维,最坏O(n^3),最好O(n^2),过不了啊。。

但是如果逆着来——(一下我把F数组写成g数据,个人习惯,不喜勿喷)

f[i]=min(f[j]+s*g[j]+(s+t[i]-t[j])*(g[i]-g[j])+(t[i]-t[j])*g[j])=min(f[j]+(s+t[i]-t[j])*g[i])

其中,g数组和t数组都是后缀和。

为了方便处理,我们把整个reverse一下,然后就是正常的从前往后推了。

显然,这东西很适合推斜率优化。

设k<j<i,更新f[i]时f[j]比f[k]优越当且仅当f[j]+(s+t[i]-t[j])*g[i]<f[k]+(s+t[i]-t[k])*g[i]

变形得,

(f[i]-f[k])/(t[j]-t[k])<g[i]

哈哈哈,这不就一sb题吗,g[i]递增啊。

然而出题人就这么毒瘤,时间t搞成还有负数和0,所以t数组就不是单调的了。

这。。。据说x坐标不单调要平衡树或cdq啊。。。完了。

1min。

2min。

3min。

……

nhours。。。

死磕了一下别的dalao的blog,终于会了。

这里运用cdq的思想主要还是在归并排序上面。

通过构造x坐标有序的凸包来更新解。

显然,用分治来做,处理[l..r]时先把[l..mid]搞成x坐标有序的(当然要先把这段区间的答案计算出来,即先cdq(l,mid)),

然后可以构造出一个凸包,供[mid+1..r]这段区间使用。

更新好以后[mid+1..r],并不意味着[mid+1..r]的答案确定了,因为这本段区间里点还没有被本段区间的点更新过。

所以还要调用cdq(mid+1,r)。

然后最后把区间按照t从小到大排好序。

当然,在熟练之后,很容易能推出要维护一个斜率单调递增的队列(也就是下凸壳)。

续了我。。。

据说还有一种方法,能使x坐标单调,斜率不单调?留坑。

upd:12/4 19:24

明白了怎么用二分处理。当然用二分是在斜率不单调的时候用的。

那我们就要改一下这个方程:

这里(其实上面也有)运用到了“提前计算代价”的思想。

就是说,在不影响dp的无后效性的情况下,转移当前状态时,将当前影响到后面的费用计算出来。

方程:f[i]=min{f[j]+s*(g[n]-g[j])+t[i]*(g[i]-g[j])}

其中g和t都是前缀和。这个方程转自konjac大佬的博客。

然后设k<j<i,f[j]<f[k],

则(f[j]-f[k])/(g[j]-g[k])<s+t[i]。

而g是递增的,s+t[i]则不是。

这时我们不需要cdq了,但需要二分。

怎么二分?

我们发现维护的还是一个斜率单调递增的凸包,但是查询的时候,可不能和原来那样,秉承一个单调的原则取了。

因为原来如果s+t[i]是递增的,那么你删掉了一个点q[c],那么表示slope(q[c],q[c+1])<s+t[i],那对于更大的s+t[i],这个点就没有用了,直接pop掉就好了。

但是现在情况不同,不能pop。那么,我们可以查找一个ret点,使ret是满足slope(q[ret],q[ret+1)>=s+t[i]的点中,slope(q[ret],q[ret+1)最小的一个。

换言之,就是最靠前的那一个。那我们可以通过二分查找来实现,不过需要判断边界情况。

复杂度仍然是O(nlogn)的。

code(cdq):

 #include <cstdio>
 #include <cstring>
 #include <algorithm>
 typedef long long LL;
 using namespace std;

 void OJ() {
     #ifndef ONLINE_JUDGE
         freopen("in.txt","r",stdin);
         freopen("out.txt","w",stdout);
     #endif
 }

 namespace fastIO {
     #define gec(c) getchar(c)
     #define puc(c) putchar(c)
     char ch;
     inline int read() {
         ,f=; ch=getchar();
         ') {
             if (ch=='-') f=-f;
             ch=gec();
         }
         ') {
             x=(x<<)+(x<<)+(ch^);
             ch=getchar();
         }
         return x*f;
     }
     ];
     template <class T> inline void write(T x) {
         ) {
             puc('); return;
         }
         ) x=-x,puc('-');
         ; x; x/=) nnn[++ttt]=x%;
         );
     }
 } using namespace fastIO;

 ;
 int n,L,R; LL s;
 struct point {
     LL x,y;
     point () {}
     point (LL i,LL j) :
         x(i),y(j) {}
 } q[N];
 struct mis {
     int i; LL t,g,v,f;
 } a[N],o[N];
 inline double slope (point u,point v) {
     ?1e10:-1e10;
     return 1.0*(v.y-u.y)/(v.x-u.x);
 }
 inline void insert (point u) {
     for ( ; L<R; ) {
         ],q[R])>slope(q[R],u)) {
             --R;
         } else break;
     }
     q[++R]=u;
 }
 inline LL reply (LL k) {
     for ( ; L<R; ) {
         ])<1.0*k) {
             ++L;
         } else break;
     }
     return q[L].y-k*q[L].x;
 }
 #define M ((l)+(r)>>1)
 inline void cdq (int l,int r) {
     if (l>=r) return;
     cdq(l,M);
     L=,R=;
     for (int i=l; i<=M; ++i) {
         insert(point(a[i].t,a[i].f));
     }
     ; i<=r; ++i) {
         a[i].f=min(a[i].f,reply(a[i].g)+a[i].v);
     }
     cdq(M+,r);
     ;
     for (int i=l; i<=r; ++i) {
         if (v>r||(a[u].t<a[v].t&&u<=M)) o[i]=a[u++];
         else o[i]=a[v++];
     }
     for (int i=l; i<=r; ++i) a[i]=o[i];
 }
 inline bool cmp (const mis &u,const mis &v) {
     return u.i<v.i;
 }
 int main() {
     OJ();
     n=read(),s=read();
     ; i<=n; ++i) {
         a[i].t=read(),a[i].g=read();
         a[i].i=n-i+;
     }
     for (int i=n; i; --i) {
         a[i].t+=a[i+].t,a[i].g+=a[i+].g;
         a[i].f=a[i].v=(s+a[i].t)*a[i].g;
     }
     reverse(a+,a++n);
     cdq(,n);
     sort(a+,a++n,cmp);
     write(a[n].f);
     ;
 }

code(二分):

 #include <cstdio>
 #include <cstring>
 #include <algorithm>
 typedef long long LL;
 using namespace std;

 void OJ() {
     #ifndef ONLINE_JUDGE
         freopen("in.txt","r",stdin);
         freopen("out.txt","w",stdout);
     #endif
 }

 namespace fastIO {
     #define gec(c) getchar(c)
     #define puc(c) putchar(c)
     char ch;
     inline int read() {
         ,f=; ch=getchar();
         ') {
             if (ch=='-') f=-f;
             ch=gec();
         }
         ') {
             x=(x<<)+(x<<)+(ch^);
             ch=gec();
         }
         return x*f;
     }
     ];
     template <class T> inline void write(T x) {
         ) {
             puc('); return;
         }
         ) x=-x,puc('-');
         ; x; x/=) nnn[++ttt]=x%;
         );
     }
 } using namespace fastIO;

 ;
 const LL inf=1e12;
 int n,L,R; LL s;
 struct point {
     LL x,y;
     point () {}
     point (LL i,LL j) :
         x(i),y(j) {}
 } q[N],opt;
 struct mis {
     LL t,g,f;
 } a[N];
 inline double slope (point u,point v) {
     if (v.x==u.x) return v.y>u.y?inf:-inf;
     return 1.0*(v.y-u.y)/(v.x-u.x);
 }
 inline void insert (point u) {
     for ( ; L<R; ) {
         ],q[R])>=slope(q[R],u)) {
             --R;
         } else break;
     }
     q[++R]=u;
 }
 inline point reply (LL k) {
     if (L==R) return q[L]; else
     ],q[R])<k) return q[R]; else
     ])>=k) return q[L];
     ,mid,ret;
     while (l<=r) {
         mid=(l+r)>>;
         ])>=k) {
             ret=mid,r=mid-;
         } ;
     }
     return q[ret];
 }
 int main() {
     OJ();
     n=read(),s=read(),a[].t=a[].g=a[].f=;
     ; i<=n; ++i) a[i].t=read(),a[i].g=read();
     ; i<=n; ++i) a[i].t+=a[i-].t;
     ; i<=n; ++i) a[i].g+=a[i-].g;
     L=,R=,q[]=point(,);
     ; i<=n; ++i) {
         LL k=s+a[i].t; opt=reply(k);
         a[i].f=opt.y-k*opt.x+s*a[n].g+a[i].t*a[i].g;
         insert(point(a[i].g,a[i].f));
     }
     write(a[n].f);
     ;
 }

[bzoj P2726] [SDOI2012]任务安排的更多相关文章

  1. BZOJ 2726: [SDOI2012]任务安排( dp + cdq分治 )

    考虑每批任务对后面任务都有贡献, dp(i) = min( dp(j) + F(i) * (T(i) - T(j) + S) ) (i < j <= N)  F, T均为后缀和. 与j有关 ...

  2. BZOJ 2726: [SDOI2012]任务安排 [斜率优化DP 二分 提前计算代价]

    2726: [SDOI2012]任务安排 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 868  Solved: 236[Submit][Status ...

  3. bzoj 2726: [SDOI2012]任务安排【cdq+斜率优化】

    cdq复健.jpg 首先列个n方递推,设sf是f的前缀和,st是t的前缀和: \[ f[i]=min(f[j]+s*(sf[n]-sf[j])+st[i]*(sf[i]-sf[j])) \] 然后移项 ...

  4. bzoj 2726: [SDOI2012]任务安排

    Description 机 器上有N个需要处理的任务,它们构成了一个序列.这些任务被标号为1到N,因此序列的排列为1,2,3...N.这N个任务被分成若干批,每批包含相邻的 若干任务.从时刻0开始,这 ...

  5. BZOJ.2726.[SDOI2012]任务安排(DP 斜率优化)

    题目链接 数据范围在这:https://lydsy.com/JudgeOnline/wttl/thread.php?tid=613, 另外是\(n\leq3\times10^5\). 用\(t_i\) ...

  6. BZOJ 2726 [SDOI2012] 任务安排 - 斜率优化dp

    题解 转移方程与我的上一篇题解一样 : $S\times sumC_j  + F_j = sumT_i \times sumC_j + F_i - S \times sumC_N$. 分离成:$S\t ...

  7. bzoj 2726 [SDOI2012]任务安排(斜率DP+CDQ分治)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2726 [题意] 将n个任务划分成若干个块,每一组Mi任务花费代价(T+sigma{ t ...

  8. BZOJ 2726: [SDOI2012]任务安排 斜率优化 + 凸壳二分 + 卡精

    Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) # ...

  9. 【BZOJ2726】[SDOI2012]任务安排 斜率优化+cdq分治

    [BZOJ2726][SDOI2012]任务安排 Description 机器上有N个需要处理的任务,它们构成了一个序列.这些任务被标号为1到N,因此序列的排列为1,2,3...N.这N个任务被分成若 ...

随机推荐

  1. mika的模板库

    二分图最大匹配: 1.匈牙利算法:注意dfs中是dfs(c[w[i]]),搜索的是与之匹配的点. #include<cstdio> #include<cstring> ],w[ ...

  2. Centos7下安装配置elasticsearch 6.3.1

    1)下载 Elasticsearch 6.3.1 地址:https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.3.1 ...

  3. Python的伪造数据生成器:Faker

    我们在开发中常常需要利用一些假数据来做测试,这种时候就可以使用 Faker 来伪造数据从而用来测试. Faker 是一个可以让你生成伪造数据的Python包.当你需要初始化数据库,创建美观的XML文档 ...

  4. (Review cs231n) CNN in Practice

    Make the most of your data Data augmentation 加载图像后,对图像做一些变化,这些变换不改变图像的标签. 通过各种变换人为的增大数据集,可以避免过拟合提高模型 ...

  5. 前端使用node.js的http-server开启一个本地服务器

    前端使用node.js的http-server开启一个本地服务器 在写前端页面中,经常会在浏览器运行HTML页面,从本地文件夹中直接打开的一般都是file协议,当代码中存在http或https的链接时 ...

  6. ie8下new Date()指定时间

    项目开发中很可能会需要创建一个指定日期的时间对象,火狐浏览器可以直接使用new Date('yyyy-mm-dd')生成时间,但是在ie8下就会发现生成的时间输出的是NaN-NaN-NaN.为了兼容可 ...

  7. 获取某个元素第一次出现在数组(json数组)的索引

    function firstIndex(arr, text) { // 若元素不存在在数组中返回-1 let firstVal = -1; for (let i = 0; i < arr.len ...

  8. 小试wsl

    安装 管理员权限运行powershell,执行如下命令: Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Su ...

  9. opencv学习之路(41)、人脸识别

    一.人脸检测并采集个人图像 //take_photo.cpp #include<opencv2/opencv.hpp> using namespace cv; using namespac ...

  10. 详解Bootstrap实现基本布局的方法

    看到了一篇 20 分钟打造 Bootstrap 站点的文章,内容有点老,重新使用bootstrap教程实现一下,将涉及的内容也尽可能详细说明. 1. 创建基本的页面我们先创建一个基本的 HTML 模板 ...