青蛙

题目描述

 

有n 块石头排成一行,从左到右依次编号为1到n,相邻两块石头之间的距离为1。

 

有m 只青蛙,开始时都位于1 号石头,它们都需要跳到n 号石头上。青蛙只能跳到更靠右的石头上。如果第i 只青蛙的某次跳跃的距离超过d,那么需要付出ci的代价。

 

求出满足以下两个条件时,总代价的最小值:

 

(1)石头a1,a2,a3,…,ak 必须被跳到恰好一次。

 

(2)其它石头(不包含1号石头和n号石头)不能被跳到。

 

有多组数据。

输入格式

 

第一行一个整数t表示数据组数。

 

每组数据第一行四个整数n,m,k,d,第二行m个整数c1~cm,第三行k个整数a1~ak。

输出格式

每组数据输出一行一个整数表示答案。

样例输入

2

10 2 3 3

4 7

4 8 7

10 2 2 3

4 7

9 5

 

样例输出

4

15

 

题解

 

贪心。

 把ci排序。

 为保证总代价最小,ci越小的青蛙付出代价的次数要越少。ci大的青蛙,能不付出代价最好。

 先计算可以踩的相邻两块石头之间的距离,如果每两块石头间的距离都不超过d,就一定有青蛙可以不花代价跳到终点。计算有多少青蛙可以不花代价跳到终点,让ci最大的几只青蛙跳过去。

 怎么算呢?题解有3种方法:

 首先求出最多能有多少只青蛙不花费代价到达 n,记为 p。

 方法一:考虑每相邻 d 块石头的可以经过次数之和,p 为这个的最小值。

 方法二:二分答案,维护青蛙的位置,每次有空石头时将最靠左的跳过去。

 方法三:贪心,对于每只青蛙,不停选择能跳的最靠右的石头跳过去。

 

 我打的是方法一,这里再解释一下:

 n块石头有的不能踩,有的能踩,“每相邻 d 块石头的可以经过次数之和”就是指每相邻d块石头中可以踩的石头数。每相邻 d 块石头为一组,因为青蛙不花代价可以跳的最大距离为d,每组青蛙跳到相邻的下一组都不用花代价。如果每块石头站一只青蛙,这些青蛙都可以不花代价跳到下一组。但是每组可以站的青蛙数不同,取最小值。c 最大的 p 只青蛙不花费代价,其余青蛙分别花费一次代价直接从 1 跳到 n。

 如果存在两块相邻可踩石头近的距离大于d,那么所有青蛙都要花费代价,最优策略是 c 最小的一只青蛙跳过这 k 块石头,其余青蛙直接从 1 跳到 n。

 

注意!!!  题目没说石头a1,a2,a3,…,ak是有序的,记得排序!

 

 

#include <algorithm>
#include <cstdio>
int T,l,n,m,d,a[100005];
long long c[100005],ans;
int main()
{
//    freopen("frog.in","r",stdin);
//    freopen("frog.out","w",stdout);
    int i,j,s;
    long long t;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d%d%d",&l,&m,&n,&d);
        for (i=1;i<=m;i++)
          scanf("%lld",&c[i]);
        for (i=1;i<=n;i++)
          scanf("%d",&a[i]);
        std::sort(c+1,c+m+1);
        std::sort(a+1,a+n+1);
        a[0]=1;     a[n+1]=l;
        ans=0;
        for (i=1,t=0;i<=n+1;i++)
          if (a[i]-a[i-1]>d)
            t++;
        if (t==0)
        {
            for (i=1,j=1,s=m;i<=n;i++)
            {
                while (j<=n+1 && a[j]-a[i-1]<=d) j++;
                if (j<=n)
                {
                    if (j-i<s) s=j-i;
                }
                else break;
            }
            for (i=1;i<=m-s;i++) 
              ans+=c[i];
        }
        else
        {
            ans=t*c[1];   
            for (i=2;i<=m;i++)
              ans+=c[i];
        }        
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2018-02-28 20:09  SAKURA12  阅读(431)  评论(0编辑  收藏  举报