zoukankan      html  css  js  c++  java
  • [luogu5574]任务分配问题

    首先暴力dp,令$f_{i,j}$表示前$i$个点划分为$j$段,即有转移$f_{i,j}=min f_{k-1,j-1}+calc(k,i)$(其中$calc(i,j)$表示求区间$[i,j]$的顺序对数)

    可以先枚举$j$,记$g_{i}=f_{i,j-1}$,则$f_{i}=min g_{k-1}+calc(k,i)$,先$o(k)$枚举以下层数,快速支持上述转移

    令$mn_{i}$为取到最小值的最小的$k$,即有$f_{i}=g_{mn_{i}-1}+calc(mn_{i},i)$,则有$mn_{i}le mn_{i+1}$(即决策单调性),证明如下:

    反证法,若$mn_{i}>mn_{i+1}$(为方便表示,以下记$x=mn_{i}$、$y=mn_{i+1}$),则由于其都是最小的转移,则有:$g_{x-1}+calc(x,i)le g_{y-1}+calc(y,i)$,$g_{x-1}+calc(x,i+1)ge g_{y-1}+calc(y,i+1)$

    将第二个式子乘上-1后与第一个式子分别相加,可得$calc(x,i)-calc(x,i+1)le calc(y)-calc(y,i+1)$

    考虑顺序对的意义(即代入顺序对的式子),即$-sum_{j=x}^{i}[a_{j}le a_{i+1}]le -sum_{j=y}^{i}[a_{j}le a_{i+1}]$

    由于$x>y$,将右式加过来,即$sum_{j=y}^{x-1}[a_{j}le a_{i+1}]le 0$,由于左式非负,因此必然取等号

    考虑这个式子是由最初两个式子相加,因此也应取到等号,即$g_{x-1}+calc(x,i)=g_{y-1}+calc(y,i)$,这与$mn_{i}$为最小的$k$矛盾

    接下来考虑如何来维护这个$mn_{i}$,直接整体二分,即求出$mn_{mid}$,然后划分为两部分即可

    但还有一个问题,考虑如何求$mn_{mid}$,假设询问区间为$[l,r]$,答案(即$mn_{i}$)对应区间为$[x,y]$,此时如果暴力求$[y,mid]$内的顺序对数复杂度显然是不对的,因此考虑优化

    类似莫队,维护一个区间$[l',r']$以及该区间内的顺序对数,之后通过移动$l'$和$r'$(需要可持久化线段树维护移动)来得到该区间,接下来每次移动次数为$o((y-x)+(r-l))$,由此即可得总复杂度为$o(nklog^{2}n)$

    首先,每一次开始时,$l'in [x,y]$且$r'in [l,r]$(可以归纳),此时相当于要将$r'$移动到$mid$,再将$l'$移动到$y$再移动回$x$,这些年都是$o((y-x)+(r-l))$的

    之后考虑将$l'$移动回到$mn_{mid}$,进行搜索左区间,再将$r'$移动到$mid+1$来搜索右区间,最后再把$l'$和$r'$移动回最开始的状态,这样就可以保证复杂度

    (由于$|a-b|+|b-c|ge |a-c|$,这个移动并不需要去实现,而只是证明复杂度)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 25005
     4 #define mid (l+r>>1)
     5 int V,n,k,ll,rr,a[N],rt[N],tr[N*20],ls[N*20],rs[N*20];
     6 long long sum,g[N],f[N];
     7 int New(int k){
     8     tr[++V]=tr[k];
     9     ls[V]=ls[k];
    10     rs[V]=rs[k];
    11     return V;
    12 }
    13 void update(int &k,int l,int r,int x){
    14     k=New(k);
    15     tr[k]++;
    16     if (l==r)return;
    17     if (x<=mid)update(ls[k],l,mid,x);
    18     else update(rs[k],mid+1,r,x);
    19 }
    20 int query(int k,int l,int r,int x,int y){
    21     if ((!k)||(l>y)||(x>r))return 0;
    22     if ((x<=l)&&(r<=y))return tr[k];
    23     return query(ls[k],l,mid,x,y)+query(rs[k],mid+1,r,x,y);
    24 }
    25 int calcl(int x,int y){
    26     return query(rt[y],1,n,a[x]+1,n)-query(rt[x],1,n,a[x]+1,n);
    27 }
    28 int calcr(int x,int y){
    29     return query(rt[y-1],1,n,1,a[y]-1)-query(rt[x-1],1,n,1,a[y]-1);
    30 }
    31 long long calc(int x,int y){
    32     while (rr<y)sum+=calcr(ll,++rr);
    33     while (x<ll)sum+=calcl(--ll,rr);
    34     while (ll<x)sum-=calcl(ll++,rr);
    35     while (y<rr)sum-=calcr(ll,rr--);
    36     return sum;
    37 }
    38 void dfs(int l,int r,int x,int y){
    39     if (l>r)return;
    40     int s=0,k=0;
    41     f[mid]=0x3f3f3f3f;
    42     for(int i=x;i<=min(mid,y);i++){
    43         int s=g[i-1]+calc(i,mid);
    44         if (s<f[mid]){
    45             f[mid]=s;
    46             k=i;
    47         }
    48     }
    49     dfs(l,mid-1,x,k);
    50     dfs(mid+1,r,k,y);
    51 }
    52 int main(){
    53     scanf("%d%d",&n,&k);
    54     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    55     for(int i=1;i<=n;i++){
    56         rt[i]=rt[i-1];
    57         update(rt[i],1,n,a[i]);
    58     }
    59     ll=1,rr=0;
    60     for(int i=1;i<=n;i++)f[i]=calc(1,i);
    61     for(int i=1;i<k;i++){
    62         memcpy(g,f,sizeof(g));
    63         dfs(1,n,1,n);
    64     }
    65     printf("%d",f[n]);
    66 } 
    View Code
  • 相关阅读:
    xml 总结(一)数据岛,命名空间
    activiti designer 安装到 myeclipse
    activiti5.15 学习笔记
    goole网址IP
    form 中Enctype=multipart/form-data 的作用
    上传文件form表单enctype="multipart/form-data"传值解决办法(代原代码)
    淘宝初始化样式
    js闭包使用之处
    CSS Sprites
    iframe用的场景
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14183287.html
Copyright © 2011-2022 走看看