codeforces#1154F. Shovels Shop (dp)

题目链接:

http://codeforces.com/contest/1154/problem/F

题意:

 有$n$个物品,$m$条优惠

每个优惠的格式是,买$x_i$个物品,最便宜的$y_i$个物品免费

每条优惠可以无限次使用(当时以为每个优惠只能用一次)

可以买一个物品,不参与优惠

求买k个物品的最低花费

数据范围:

$1 le n, m le 2 cdot 10^5, 1 le k le min(n, 2000)$
$1 le a_i le 2 cdot 10^5$
$1 le y_i le x_i le n$

分析: 

太蠢了,一开始以为每条优惠只能用一次,并且以为,优惠都有一个使用次序,所以先给优惠排序,然后枚举优惠更新dp数组

原来每个优惠能用无限次,那么我们再加入一条$(1,0)$优惠,枚举购买长度,用每个优惠对它更新

虽然两种方法的状态定义得相同。。。。

ac代码:

#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
#define mak make_pair
using namespace std;
const int maxn=2e5+3000;
const ll INF=1e18;
int price[maxn],x[maxn],y[maxn];
ll sum[maxn],dp[2005];
int main()
{
    int n,m,k;
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1; i<=n; i++)scanf("%d",&price[i]);
    sort(price+1,price+1+n);
    for(int i=1;i<=k;i++)sum[i]=sum[i-1]+price[i];
    for(int i=1; i<=m; i++)
        scanf("%d %d",&x[i],&y[i]);
    x[m+1]=1;y[m+1]=0;
    for(int i=0; i<=k; i++)dp[i]=INF;
    dp[0]=0;
    for(int i=1;i<=k;i++)
    {
        for(int j=1;j<=m+1;j++)
            if(i-x[j]>=0)
                dp[i]=min(dp[i],dp[i-x[j]]+sum[i]-sum[i-x[j]+y[j]]);
    }
    printf("%lld
",dp[k]);
    return 0;
}

  

原文地址:https://www.cnblogs.com/carcar/p/10764689.html