• 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
    ",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
    ",f[n]);
    48     //FOR(i,1,n) {
    49     //    printf("%d %d
    ",F[i],f[i]-F[n]*T[i]+F[i]*T[i]-s*F[i]);
    50     //}
    51     return 0;
    52 }
    View Code
  • 相关阅读:
    第十二章学习笔记
    UVa OJ 107 The Cat in the Hat (戴帽子的猫)
    UVa OJ 123 Searching Quickly (快速查找)
    UVa OJ 119 Greedy Gift Givers (贪婪的送礼者)
    UVa OJ 113 Power of Cryptography (密文的乘方)
    UVa OJ 112 Tree Summing (树的求和)
    UVa OJ 641 Do the Untwist (解密工作)
    UVa OJ 105 The Skyline Problem (地平线问题)
    UVa OJ 100 The 3n + 1 problem (3n + 1问题)
    UVa OJ 121 Pipe Fitters (装管子)
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5362036.html
Copyright © 2020-2023  润新知