zoukankan      html  css  js  c++  java
  • 青蛙

    题目描述

    有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
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    js 数组相减
    js 对象数组去重
    vue 首次不触发watch的解决方法
    "神药"推荐--紫花地丁
    openstack 平台添加 nvidia vGPU
    string易错点整理总结
    CentOS安装图形界面
    CentOs安装ssh和scp
    数组把0移到末尾
    Windows下Celery安装与下使用
  • 原文地址:https://www.cnblogs.com/rabbit1103/p/8485474.html
Copyright © 2011-2022 走看看