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

【题目链接】

http://www.lydsy.com/JudgeOnline/problem.php?id=2726

【题意】

将n个任务划分成若干个块,每一组Mi任务花费代价(T+sigma{ tj }+s)*sima{ fi },j属于Mi,T为当前时间,问最小代价。

【思路】

设f[i]为将前i个任务划分完成的最小费用,Ti Fi分别表示t和f的前缀和,则不难写出转移方程式:

f[i]=min{ f[j]+(F[n]-F[j])*(T[i]-T[j]+s) },1<=j<=i-1

经过整理得到:

f[i]=min{ -T[i]*F[j]+(f[j]-F[n]*T[j]+F[j]*T[j]-s*F[j]) }

设X(i)=F[i],Y(i)=f[j]-F[n]*T[j]+F[j]*T[j]-s*F[j],a(i)=T[i]则有:

f[i]=min{ -a(i)*X(j)+Y(j) }

则我们需要:

min p = -a(i)*X(j)+Y(j)

即最小化直线方程:Y(j)=a(i)*X(j)+p的截距。

如果时间没有负数的话(出题人神脑洞<_<,这个题可以直接上单调队列维护下凸线。事实上这个算法可以得到60分。

有了负数以后因为斜率不满足随x单调,所以不能使用单调队列。

然后这道题就需要用splay或CDQ分治解。

Splay写法还是不会=-=,CDQ分治的处理和 这道题 类似,就不再赘述了。

需要注意的:x,y可能到达long long级别,所以不要直接除得slop

        运算过程中long long的标识。

        归并数组的时候几个小条件。

【代码】

  1 #include<set>
  2 #include<cmath>
  3 #include<queue>
  4 #include<vector>
  5 #include<cstdio>
  6 #include<cstring>
  7 #include<iostream>
  8 #include<algorithm>
  9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 11 #define rep(a,b,c) for(int a=(b);a>=(c);a--)
 12 using namespace std;
 13
 14 typedef long long ll;
 15 const int N = 5e5+10;
 16 const ll inf = 1e18;
 17
 18 ll read() {
 19     char c=getchar();
 20     ll f=1,x=0;
 21     while(!isdigit(c)) {
 22         if(c==‘-‘) f=-1; c=getchar();
 23     }
 24     while(isdigit(c))
 25         x=x*10+c-‘0‘,c=getchar();
 26     return x*f;
 27 }
 28
 29 struct Pt
 30 {
 31     ll x,y,k;
 32     int id;
 33     bool operator < (const Pt& rhs) const
 34     {
 35         return k<rhs.k;
 36     }
 37 }q[N],t[N];
 38
 39 bool cmp(const Pt& a,const Pt& b)
 40 {
 41     return a.x<b.x || a.x==b.x&&a.y<b.y;
 42 }
 43
 44 int T[N],F[N],st[N],top,n,s; ll f[N];
 45
 46 ll U(int j,int k)
 47 {
 48     return (ll)q[k].y-q[j].y;
 49 }
 50 ll D(int j,int k)
 51 {
 52     return (ll)q[k].x-q[j].x;
 53 }
 54
 55 void solve(int l,int r)
 56 {
 57     if(l==r) {
 58         q[l].x=(ll)F[l];
 59         q[l].y=(ll)f[l]-(ll)F[n]*T[l]+(ll)F[l]*T[l]-(ll)s*F[l];
 60         return ;
 61     }
 62     int mid=l+r>>1;
 63     int l1=l,l2=mid+1;
 64     FOR(i,l,r) {
 65         if(q[i].id>mid) t[l2++]=q[i];
 66         else t[l1++]=q[i];
 67     }
 68     memcpy(q+l,t+l,sizeof(Pt)*(r-l+1));
 69     solve(l,mid);
 70     top=0;
 71     FOR(i,l,mid) {
 72         while(top>1 && (ll)U(st[top-1],st[top])*D(st[top-1],i)>(ll)U(st[top-1],i)*D(st[top-1],st[top])) top--;
 73         st[++top]=i;
 74     }
 75     int j=1;
 76     FOR(i,mid+1,r) {
 77         while(j<top && U(st[j],st[j+1])<(ll)q[i].k*D(st[j],st[j+1])) j++;
 78         f[q[i].id]=min(f[q[i].id],-(ll)q[i].k*q[st[j]].x+q[st[j]].y+(ll)F[n]*(T[q[i].id]+s));
 79     }
 80     solve(mid+1,r);
 81     l1=l,l2=mid+1;
 82     FOR(i,l,r) {
 83         if((l2>r||cmp(q[l1],q[l2]))&&l1<=mid) t[i]=q[l1++];
 84         else t[i]=q[l2++];
 85     }
 86     memcpy(q+l,t+l,sizeof(Pt)*(r-l+1));
 87 }
 88
 89 int main()
 90 {
 91 //    freopen("in.in","r",stdin);
 92 //    freopen("out.out","w",stdout);
 93     n=read(),s=read();
 94     FOR(i,1,n)
 95         T[i]=read(),T[i]+=T[i-1],
 96         F[i]=read(),F[i]+=F[i-1];
 97     FOR(i,1,n) {
 98         q[i].id=i;
 99         q[i].k=T[i];
100         f[i]=inf;
101     }
102     sort(q+1,q+n+1);
103     solve(0,n);
104     printf("%lld\n",f[n]);
105     return 0;
106 }

简单DP(20分)

 1 #include<set>
 2 #include<cmath>
 3 #include<queue>
 4 #include<vector>
 5 #include<cstdio>
 6 #include<cstring>
 7 #include<iostream>
 8 #include<algorithm>
 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
11 #define rep(a,b,c) for(int a=(b);a>=(c);a--)
12 using namespace std;
13
14 typedef long long ll;
15 const int N = 2e5+10;
16 const ll inf = 1e18+10;
17
18 ll read() {
19     char c=getchar();
20     ll f=1,x=0;
21     while(!isdigit(c)) {
22         if(c==‘-‘) f=-1; c=getchar();
23     }
24     while(isdigit(c))
25         x=x*10+c-‘0‘,c=getchar();
26     return x*f;
27 }
28
29 ll T[N],F[N],f[N],pre[N],n,s;
30
31 int main()
32 {
33     freopen("in.in","r",stdin);
34     freopen("outr.out","w",stdout);
35     n=read(),s=read();
36     FOR(i,1,n)
37         T[i]=read(),T[i]+=T[i-1],F[i]=read(),F[i]+=F[i-1]    ;
38     FOR(i,1,n) {
39         f[i]=inf;
40         FOR(j,0,i-1) {
41             //f[i]=min(f[i],f[j]+(F[n]-F[j])*(T[i]-T[j]+s));
42             int tmp=-T[i]*F[j]+(f[j]-F[n]*T[j]+F[j]*T[j]-s*F[j]);
43             if(tmp<f[i]) pre[i]=j,f[i]=tmp;
44         }
45         f[i]+=F[n]*(T[i]+s);
46     }
47     printf("%lld\n",f[n]);
48     //FOR(i,1,n) {
49     //    printf("%d %d\n",F[i],f[i]-F[n]*T[i]+F[i]*T[i]-s*F[i]);
50     //}
51     return 0;
52 }

时间: 2024-10-29 19:06:23

bzoj 2726 [SDOI2012]任务安排(斜率DP+CDQ分治)的相关文章

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

2726: [SDOI2012]任务安排 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 868  Solved: 236[Submit][Status][Discuss] Description 机器上有N个需要处理的任务,它们构成了一个序列.这些任务被标号为1到N,因此序列的排列为1,2,3...N.这N个任务被分成若干批,每批包含相邻的若干任务.从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti.在每批任务开始前,机器需要启

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

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

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

考虑每批任务对后面任务都有贡献, dp(i) = min( dp(j) + F(i) * (T(i) - T(j) + S) ) (i < j <= N)  F, T均为后缀和. 与j有关的量只有t = dp(j) - F(i) * T(j) , 我们要最小化它. dp(j)->y, T(j)->x, 那么y = F(i) * x + t, 就是给一些点和一个斜率...然后最小化截距, 显然维护下凸包就可以了. 然后因为无比坑爹的出题人....时间可以为负数, 所以要用平衡树维护(

bzoj 1492 [NOI2007]货币兑换Cash(斜率dp+cdq分治)

Description Input 第一行两个正整数N.S,分别表示小Y 能预知的天数以及初始时拥有的钱数. 接下来N 行,第K 行三个实数AK.BK.RateK,意义如题目中所述 Output 只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的金钱 数目.答案保留3 位小数. Sample Input 3 100 1 1 1 1 2 2 2 2 3 Sample Output 225.000 HINT 测试数据设计使得精度误差不会超过10-7.对于40%的测试数据,满足N

斜率dp cdq 分治

f[i] = min { f[j] + sqr(a[i] - a[j]) } f[i]= min { -2 * a[i] * a[j] + a[j] * a[j] + f[j] } + a[i] * a[i] 由于a[i]不是单调递增的,不能直接斜率dp. 考虑有cdq分治来做,复杂度(nlog2n) 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm&

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])) \] 然后移项: \[ f[i]=f[j]+s*sf[n]-s*sf[j]+st[i]*sf[i]-st[i]*sf[j] \] \[ f[i]=f[j]+s*sf[n]+st[i]*sf[i]-s*sf[j]-st[i]*sf[j] \] \[ f[i]=f[j]+s*sf[n]+st[i]*sf[i]-sf[

bzoj 2726: [SDOI2012]任务安排

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

【bzoj3672】[Noi2014]购票 斜率优化+CDQ分治+树的点分治

题目描述 给出一棵以1为根的带边权有根树,对于每个根节点以外的点$v$,如果它与其某个祖先$a$的距离$d$不超过$l_v$,则可以花费$p_vd+q_v$的代价从$v$到$a$.问从每个点到1花费的最小代价(中途可以经停其它点) 输入 第 1 行包含2个非负整数 n,t,分别表示城市的个数和数据类型(其意义将在后面提到).输入文件的第 2 到 n 行,每行描述一个除SZ之外的城市.其中第 v 行包含 5 个非负整数 $f_v,s_v,p_v,q_v,l_v$,分别表示城市 v 的父亲城市,它到

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

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