zoukankan      html  css  js  c++  java
  • [World Final 2016] Branch Assignment

    链接

    PDF

    bzoj

    先求出正置边和反置边时b+1到前b个点的最短路dis[0/1][x](x∈[1,b]),

    令D[x]=dis[0][x]+dis[1][x]

    然后分组后每个x对代价的贡献为D[x]*(所在组中元素个数-1)

    考虑DP决策分组过程,发现没有一个很好的序,

    不过为了使得代价小,应该把D小的放在个数大的组里,D大的放在个数少的组里

    由此可以想出,应该是大小相近的元素放在了同一组中,这意味着,先排序,在划分成s段,的所有情况包含了原问题的最优解

    于是把D[1~b]排序后,有方程

    $f[i][j]=MIN_{k=0}^{j-1}[f[i-1][k]+(j-k-1)*(sum[j]-sum[k])]$

    $O(n^3)$

    其中:f[i][j]表示把前j个分成i组的最小值,sum为D的前缀和

    非法状态均置为INF

    由于可以粗略的知道这个东西在j确定,i为自变量的函数图像上有凸性

    (可以玄学地认为,最开始的时候,多划分一刀可以造成很大的改变,随着划分次数越来越多,多划分一刀的改变越来越微小)

    于是,可以使用带权二分来优化这一DP

    即,消去对划分次数的限制,通过二分来找到一个合适的划分附加代价,使得即使不限制划分次数,最后的最优解也恰好满足我们对划分数的限制

    这样有了一个新的方程

    $f'[j]=MIN_{k=0}^{j-1}[f'[k]+(j-k-1)*(sum[j]-sum[k])]+C$

    $O(n^2log)$

    考虑优化转移过程

    拆开方程得到

    $f'[j]=MIN_{k=0}^{j-1}[f'[k]+(k+1)sum[k]-ksum[j]-jsum[k]]+(j-1)sum[j]+C$

    在方程中

    当固定j不动时

    随k增加,f'[k]+(k+1)sum[k]项增加,-ksum[j]-jsum[k]项减小

    而随j的增加,含j的项(即-ksum[j]-jsum[k])对答案的影响加剧,于是,随j的增加,j的最优决策中的k会单调变大(随j的增加,我们决策时更为看重含j项,为了使含j项减小,我们试图使用更大的k)

    这意味着这个方程有决策单调性

    本题通过带权二分和决策单调性优化可以做到$O(nlog^2)$

    (感觉最近状态很差,午休一直睡不着来着,几个月了吧,先是用N^2log给方哥号上贡献了半屏T,又以为可以nlog做,然后贡献了半屏Wa,最后才发现决策单调性)

    代码:

      1 #include<queue>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #define LL long long
      6 #define P pair <int ,int >
      7 using namespace std;
      8 priority_queue <P ,vector <P > ,greater <P > > PQ ;
      9 int n,b,s,r;
     10 struct INP{
     11     int u,v,val;
     12 }inp[50010];
     13 struct ss{
     14     int to,next,val;
     15 }e[50010];
     16 int first[5010],num;
     17 LL d[5010],f[5010],sum[5010];
     18 int lin[5010],dis[5010],que[5010],grt_st[5010];
     19 void build(int ,int ,int );
     20 void dij(int );
     21 bool check(LL );
     22 LL ask(int ,int );
     23 int main()
     24 {
     25     int i,j,k,l;
     26     LL L,R,mid;
     27     scanf("%d%d%d%d",&n,&b,&s,&r);
     28     for(i=1;i<=r;i++){
     29         scanf("%d%d%d",&inp[i].u,&inp[i].v,&inp[i].val);
     30         build(inp[i].u,inp[i].v,inp[i].val);
     31     }
     32     dij(b+1);
     33     for(i=1;i<=b;i++)    d[i]=dis[i];
     34     memset(first,0,sizeof(first)),num=0;
     35     for(i=1;i<=r;i++)
     36         build(inp[i].v,inp[i].u,inp[i].val);
     37     dij(b+1);
     38     for(i=1;i<=b;i++)    d[i]+=dis[i];
     39     sort(d+1,d+b+1);
     40     for(i=1;i<=b;i++)    sum[i]=sum[i-1]+d[i];
     41     L=0,R=b*sum[b],mid=(L+R)>>1;
     42     while(R-L>=3){
     43         if(check(mid))  L=mid;
     44         else    R=mid-1;
     45         mid=(L+R)>>1;
     46     }
     47     for(mid=R;mid>=L;mid--)
     48         if(check(mid)){
     49             printf("%lld
    ",f[b]-s*mid);
     50             return 0;
     51         }
     52     return 0;
     53 }
     54 void build(int f,int t,int val){
     55     e[++num].next=first[f];
     56     e[num].to=t,e[num].val=val;
     57     first[f]=num;
     58 }
     59 void dij(int S){
     60     int i,U;
     61     memset(dis,0x3f,sizeof(dis));
     62     dis[S]=0;
     63     P u,v;
     64     u.first=0,u.second=S;
     65     PQ.push(u);
     66     while(!PQ.empty()){
     67         u=PQ.top();
     68         PQ.pop();
     69         U=u.second;
     70         for(i=first[U];i;i=e[i].next)
     71             if(dis[e[i].to]>dis[U]+e[i].val){
     72                 dis[e[i].to]=dis[U]+e[i].val;
     73                 v.first=dis[e[i].to],v.second=e[i].to;
     74                 PQ.push(v);
     75             }
     76     }
     77 }
     78 bool check(LL lim){
     79     int tmp=0,i,h=0,t=1;
     80     int l,r,mid;
     81     f[0]=lin[0]=0,grt_st[0]=1;
     82     que[t]=0;
     83     for(i=1;i<=b;i++){
     84         l=h+1,r=t,mid=(l+r)>>1;
     85         while(r-l>3){
     86             if(i>=grt_st[que[mid]])    l=mid;
     87             else    r=mid-1;
     88             mid=(l+r)>>1;
     89         }
     90         for(mid=r;mid>=l;mid--)
     91             if(i>=grt_st[que[mid]]){
     92                 f[i]=ask(i,que[mid])+lim,lin[i]=lin[que[mid]]+1;
     93                 break;
     94             }
     95         if(i==b)    break;
     96         grt_st[i]=b+1;
     97         while(h<t&&grt_st[que[t]]>i&&ask(grt_st[que[t]],i)<=ask(grt_st[que[t]],que[t]))    grt_st[i]=grt_st[que[t]],t--;
     98         if(h<t){
     99             l=max(grt_st[que[t]],i+1),r=grt_st[i]-1,mid=(l+r)>>1;
    100             while(r-l>3){
    101                 if(ask(mid,i)<=ask(mid,que[t]))    r=mid;
    102                 else    l=mid+1;
    103                 mid=(l+r)>>1;
    104             }
    105             for(mid=l;mid<=r;mid++)
    106                 if(ask(mid,i)<=ask(mid,que[t])){
    107                     grt_st[i]=mid;
    108                     break;
    109                 }
    110         }
    111         if(grt_st[i]!=b+1)
    112             que[++t]=i;
    113     }
    114     return lin[b]>=s;
    115 }
    116 LL ask(int x,int typ){
    117     return f[typ]+(x-typ-1)*(sum[x]-sum[typ]);
    118 }
  • 相关阅读:
    nginx 转发配置
    Rancher中httpd证书的管理和使用
    JDK-docker
    软路由
    rancher相关
    rancher部署
    电商 好文 知识积累
    SpringBlade 接口文档 请求token接口报错
    SpringBlade 接口文档 无法访问
    电商 好文
  • 原文地址:https://www.cnblogs.com/nietzsche-oier/p/9078871.html
Copyright © 2011-2022 走看看