【Codeforces Round #185 (Div. 1) B】 CodeForces 311B Cats Transport

Description

Zxr960115 is owner of a large farm. He feeds m cute cats and employs p
feeders. There’s a straight road across the farm and n hills along the
road, numbered from 1 to n from left to right. The distance between
hill i and (i - 1) is di meters. The feeders live in hill 1.

One day, the cats went out to play. Cat i went on a trip to hill hi,
finished its trip at time ti, and then waited at hill hi for a feeder.
The feeders must take all the cats. Each feeder goes straightly from
hill 1 to n without waiting at a hill and takes all the waiting cats
at each hill away. Feeders walk at a speed of 1 meter per unit time
and are strong enough to take as many cats as they want.

For example, suppose we have two hills (d2 = 1) and one cat that
finished its trip at time 3 at hill 2 (h1 = 2). Then if the feeder
leaves hill 1 at time 2 or at time 3, he can take this cat, but if he
leaves hill 1 at time 1 he can’t take it. If the feeder leaves hill 1
at time 2, the cat waits him for 0 time units, if the feeder leaves
hill 1 at time 3, the cat waits him for 1 time units.

Your task is to schedule the time leaving from hill 1 for each feeder
so that the sum of the waiting time of all cats is minimized.

Input

The first line of the input contains three integers
n, m, p(2 ≤ n ≤ 105, 1 ≤ m ≤ 105, 1 ≤ p ≤ 100).

The second line contains n - 1 positive integers
d2, d3, …, dn(1 ≤ di < 104).

Each of the next m lines contains two integers hi and
ti(1 ≤ hi ≤ n, 0 ≤ ti ≤ 109).

Output

Output an integer, the minimum sum of waiting time of all cats.

Please, do not write the %lld specifier to read or write 64-bit
integers in С++. It is preferred to use the cin, cout streams or the
%I64d specifier.

可以发现,每只猫的信息都可以浓缩为一个值:a[i]=t[i]-d[i],即想要恰好接上这只猫,管理员的出发时间。那么,这只猫的等待时间即为管理员出发时间与这个值的差。
对a数组进行排序,这样每个管理员接走的猫一定是连续的一段。
求a[]的前缀和s[]。
dp[i][j]表示前i个管理员接走前j只猫的最少总等待时间。
那么朴素的状态转移方程即为dp[i][j]=max{dp[i-1][k]+a[j]-a[k+1]+a[j]-a[k+2]+…+a[j]-a[j-1]}。
上式可化简为dp[i-1][k]+a[j]*(j-k)-(s[j]-s[k])。
那么朴素算法的时间复杂度为O(pm^2)。
因为有a[j]*k这一项,j和k无法完全分离,考虑斜率优化。
对于k2>k1,k2比k1优的充要条件是
dp[i-1][k2]+a[j] * (j-k2)-(s[j]-s[k2])<=dp[i-1][k1]+a[j] * (j-k1)-(s[j]-s[k1])
记g(k)=dp[i-1][k]+s[k]
化简得(g(k2)-g(k1))/(k2-k1)<=a[j]。
于是维护k递增、相邻两点斜率也递增,且所有斜率都大于a[j]的单调队列,则任意相邻两点都是左边优于右边,所以队首即为最优解。
维护的时候,因为a[j]单调不减,所以随着j增大,会出现队首两元素的斜率<=a[j],也就是que[hd+1]优于que[hd],这样弹出队首。
另外,插入新的j可能使尾部不满足斜率递增。也就是k(que[tl-1],que[tl])<=k(que[tl],j)。(分别记为k1,k2)那么对于以后出现的任何一个j’,如果k1>a[j’],那么que[tl-1]优于que[tl]。如果k1<=a[j’],那么k2<=a[j’],那么j优于que[tl]。所以que[tl]永远不是最优决策,弹出。
时间复杂度优化为O(pm)。
注意边界条件。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const long long oo=1000000000233333;
int i,que[100010];
long long len[100010],a[100010],s[100010],dp[110][100010];
long long g(int k)
{
    return dp[i-1][k]+s[k];
}
int main()
{
    int j,k,m,n,p,q,x,y,z,hd,tl;
    scanf("%d%d%d",&n,&m,&p);
    for (i=2;i<=n;i++)
    {
        scanf("%d",&x);
        len[i]=len[i-1]+x;
    }
    for (i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        a[i]=y-len[x];
    }
    sort(a+1,a+m+1);
    for (i=1;i<=m;i++)
      s[i]=s[i-1]+a[i];
    for (i=1;i<=m;i++)
      dp[0][i]=oo;
    for (i=1;i<=p;i++)
    {
        hd=1;
        tl=0;
        for (j=0;j<=m;j++)
        {
            while (hd<tl&&
              g(que[hd+1])-g(que[hd])<=
              a[j]*(que[hd+1]-que[hd]))
                hd++;
            dp[i][j]=g(que[hd])+a[j]*(j-que[hd])-s[j];
            while (hd<tl&&
              (g(j)-g(que[tl]))*
              (que[tl]-que[tl-1])<=
              (g(que[tl])-g(que[tl-1]))*
              (j-que[tl]))
                tl--;
            que[++tl]=j;
        }
    }
    printf("%I64d\n",dp[p][m]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值