码迷,mamicode.com
首页 > 其他好文 > 详细

CF797F Mice and Holes

时间:2020-02-07 19:16:26      阅读:108      评论:0      收藏:0      [点我收藏+]

标签:ons   cpp   scan   tps   问题   limits   ret   mem   费用流   

Link
考虑用非模拟费用流做法解决laofu进队问题。
显然匹配不会交叉,因此每个队匹配的laofu都是一段区间。
\(f_{i,j}\)为前\(j\)个laofu进前\(j\)个队的最小距离和,对于第\(i\)个队,记\(sum_j=\sum\limits_{k=1}^j|a_k-p_j|\)
那么转移就是\(f_{i,j}=\min\limits_{k=j-c_i}^j(f_{i-1,k}+sum_j-sum_k)\)
显然最优决策点是单调的,单调队列维护即可。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<utility>
#include<algorithm>
#define fi first
#define se second
using i64=long long;
using pi=std::pair<int,int>;
const int N=5007;
int read(){int x;scanf("%d",&x);return x;}
int n,m,a[N],q[N];pi b[N];
i64 f[N][N],s[N],sum[N];
int main()
{
    n=read(),m=read(),memset(f,0x7f,sizeof f),f[0][0]=0;
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<=m;++i) b[i]={read(),read()};
    std::sort(a+1,a+n+1),std::sort(b+1,b+m+1);
    for(int i=1;i<=m;++i) s[i]=s[i-1]+b[i].se;
    if(s[m]<n) return !printf("-1");
    for(int i=1;i<=m;++i)
    {
        int l=0,r=0;
    f[i][0]=q[++r]=0;
        for(int j=1;j<=s[i]&&j<=n;++j)
        {
            f[i][j]=f[i-1][j],sum[j]=sum[j-1]+abs(a[j]-b[i].fi);
            while(j-q[l]>b[i].se||(l<=r&&f[i-1][q[l]]-sum[q[l]]>f[i-1][j]-sum[j])) ++l;
            q[++r]=j,f[i][j]=std::min(f[i][j],sum[j]+f[i-1][q[l]]-sum[q[l]]);
        }
    }
    printf("%lld",f[m][n]);
}

CF797F Mice and Holes

标签:ons   cpp   scan   tps   问题   limits   ret   mem   费用流   

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12273810.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!