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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
View Code

 

以上是关于bzoj 2726 [SDOI2012]任务安排(斜率DP+CDQ分治)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

bzoj 2726: [SDOI2012]任务安排

bzoj2726 [SDOI2012]任务安排

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

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