Codeforces 1154F - Shovels Shop - [DP]

題目連接:https://codeforces.com/contest/1154/problem/Fc++

 

題解:spa

首先,能夠肯定的是:code

  一、$(x,y)$ 裏 $x>k$ 的都不可能用;blog

  二、確定買的是 $n$ 個鏟子裏,價格前 $k$ 小的鏟子。ci

而後,咱們用 $f[i]$ 表示買前 $i$ 個鏟子,最多能夠優惠掉多少錢。get

咱們假設 $g[x]$ 表明買 $x$ 個鏟子,最多能夠不用付 $g[x]$ 個鏟子的錢。獲得狀態轉移方程:it

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

換句話說,對於 $f[i]$,咱們遍歷全部的 $j \in [0,i)$:test

  此時,咱們前 $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;
}
相關文章
相關標籤/搜索