• NOIP2018普及组摆渡车题解


    题解又双叒叕来了!

    每天一个小题解,你学废了吗?

    其实我刚开始看题时,是酱紫的

    我想我大概是废了。

    肯定是要对t 排序的。

    最初想法肯定是f[i] 表示前i个人全上车或到站的最小等待时间。

    但你能够发现如果不给出上一班车的时间的话f 根本转移不了。

    那就f[i][j] 表示最后一班车j 时开出的最小等待时间?

    数据范围打人脸,于是我就去查题解了。

    但是我们发现实际上最后一班车开出的时间一定在[t[i],t[i]+m] 之间,因为最差上一班车会在t[i]1 开出,t[i]+m1回来,如果我们让车停在那里再开出显然会让乘客白等。

    因此我们就可以改变f[i][j] 为前ii 个人全上车或到站,最后一班车从t[i]+jt[i]+j 时开出的最小等待时间。

    状态转移方程可以很容易的写出:

    f[i][j]=min(f[i][j],f[k][l]+sum(k+1,i,t[i]+j))(你得保证变量合法)

    最终答案就是min(f[n][0]f[n][m1])

    其中sum(i,j,k) 函数表示第i 人到第j人等时刻k 发车的等待时间和,显然预处理前缀和就可以O(1) 算了。

    但是这个式子也是O(n2m2)过不了怎么办?

    我们jj 的下限肯定是max(t[k]+l+mt[i],0) 的,但是真的有必要从这个下限枚举到m1 吗?

    显然,到i 上车时,比起让车等着,不如能早发就早发,所以虽然下限往上的状态f 可能会错,但答案一定不会错。

    因此没必要枚举j ,复杂度O(n2m)

    最后,放上代码

    没有,还请大家

    感谢大家的支持

    #include<bits/stdc++.h> //万能的头文件
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    int n,m,t[505],mem[505][505];
    int solve(int i,int st)
    {
        if (i==n+1)
            return 0;
        if (st<t[i]) 
            return solve(i,t[i]);
        if (mem[i][st-t[i]])//记忆化 
            return mem[i][st-t[i]];
        int sum=0,j=i;
        while (j<=n && t[j]<=st)
            sum+=t[j++];
        int best=st*(j-i)-sum+solve(j,st+m); 
        for (;j<=n;j++)
        {
            sum+=t[j];
            best=min(t[j]*(j-i+1)-sum+solve(j+1,t[j]+m),best);
        }
        return mem[i][st-t[i]]=best;
    }
    int main()
    {
        n=read(),m=read();
            t[i]=read();
        sort(t+1,t+n+1);
        cout << solve(1,0) << endl;
        return 0;
    }

     

    小蒟蒻ΩωΩ I AK IOI.
  • 相关阅读:
    Java基础-3y
    对线面试官面试系列-3y
    从零单排学Redis【青铜】
    mock官方文档
    route路由组件传递参数
    axios拦截器与vue代理设置
    Sass使用方法
    Less使用方法
    Vue-cli
    Vue-组件注册
  • 原文地址:https://www.cnblogs.com/20070618hyz/p/12728814.html
Copyright © 2020-2023  润新知