zoukankan      html  css  js  c++  java
  • Codeforces 1154F

    题目链接:https://codeforces.com/contest/1154/problem/F

    题解:

    首先,可以确定的是:

      1、$(x,y)$ 里 $x>k$ 的都不可能用;

      2、肯定买的是 $n$ 个铲子里,价格前 $k$ 小的铲子。

    然后,我们用 $f[i]$ 表示买前 $i$ 个铲子,最多可以优惠掉多少钱。

    我们假设 $g[x]$ 代表买 $x$ 个铲子,最多可以不用付 $g[x]$ 个铲子的钱。得到状态转移方程:

    $f[i] = min_{j=0}^{i-1}(f[j]+sum_{k=j+1}^{j+g[i-j]} a[k] )$

    换句话说,对于 $f[i]$,我们遍历所有的 $j in [0,i)$:

      此时,我们前 $j$ 个铲子,最多优惠掉了 $f[j]$ 的钱,那么 $(j+1) sim i$ 这 $i-j$ 个铲子,我们直接用 $g[i-j]$ 的优惠,省掉这 $i-j$ 个铲子里最便宜的 $g[i-j]$ 个铲子的钱。这样,我们就得到了一种买前 $i$ 个铲子的方案。(至于怎么求 $f[i]$,即维护所有 $j$ 对应的方案中,省钱最多的那一个方案即可。)

      那为什么不用 $g[i-j-1],g[i-j-2],cdots$ 这些优惠呢?因为假设用这些优惠能省钱更多,那么由于 $f[i]$ 是递增的,所以“$f[j+1]$ 加上用 $g[i-(j+1)]$ 的省钱量”,肯定优于,“$f[j]$ 加上用 $g[i-j]$ 的省钱量”。而“$f[j+1]$ 加上用 $g[i-(j+1)]$ 的省钱量”会在下一个 $j$ 被算到,所以不影响正确性。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> P;
    const int maxn=2e5+10;
    const int maxk=2e3+10;
    
    int n,m,k;
    int a[maxn],s[maxn];
    int g[maxk];
    int f[maxk];
    
    int main()
    {
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1,x,y;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            if(x<=k) g[x]=max(g[x],y);
        }
        sort(a+1,a+n+1);
        for(int i=1;i<=k;i++) s[i]=s[i-1]+a[i];
        for(int i=1;i<=k;i++)
        {
            f[i]=0;
            for(int j=0;j<i;j++)
                f[i]=max(f[i],f[j]+s[j+g[i-j]]-s[j]);
        }
        cout<<s[k]-f[k]<<endl;
    }
  • 相关阅读:
    ld -l选项注意事项
    linux下创建用户(转)
    delete void *
    __attribute__机制介绍(转)
    正常断开连接情况下,判断非阻塞模式socket连接是否断开
    std::thread “terminate called without an active exception”
    Android 开发手记二 C可执行程序编译实例(转帖)
    c++11 on Android
    由一段小程序看算法复杂度
    Linux守护进程的编程实现(转)
  • 原文地址:https://www.cnblogs.com/dilthey/p/10722844.html
Copyright © 2011-2022 走看看