返回顶部

The 2020 ICPC Asia Shenyang Regional Programming ContestNortheastern University, July 18, 2021 (Sunday) H - The Boomsday Project (dp)

  • 题意:每次骑车花费\(r\),有\(n\)张优惠券,每张优惠卷花费\(c_i\),使用后可以在之后的\(d_i\)天内免费骑车\(k_i\)次,\(m\)个需求,表示在\(p_i\)这一天要骑\(q_i\)次,问你最少花费多少钱满足条件。

  • 题解:首先用将次数和天数对应起来,然后遍历次数,设\(dp[i]\)表示总共骑了\(i\)次的最少花费,很明显有:\(dp[i]=dp[i-1]+r\),对于\(i\),这一次可以由某个优惠券免费骑,那么我们就可以遍历所有优惠券,因为是直接免费,所以我们的\(dp\)数组一定单调的,所以\(i\)越往前越优,那么对于某张优惠券,我们它找到能到达\(i\)的最远位置,从这个位置转移过来是最优的,同时复杂度也满足条件。

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
    int n,m,r;
    struct misaka{
        int d,k,c;
    }cp[N];
    int day[N];
    int cnt;
    ll dp[N];
    int step[N];
     
    int main() {
        scanf("%d %d %d",&n,&m,&r);
        for(int i=1;i<=n;++i){
            scanf("%d %d %d",&cp[i].d,&cp[i].k,&cp[i].c);
        }
        for(int i=1;i<=m;++i){
            int p,q;
            scanf("%d %d",&p,&q);
            while(q--) day[++cnt]=p;
        }
        sort(day+1,day+1+cnt);
        for(int i=1;i<=cnt;++i) dp[i]=0,step[i]=1;
        for(int i=1;i<=cnt;++i){
            dp[i]=dp[i-1]+r;
            for(int j=1;j<=n;++j){
                while(day[step[j]]+cp[j].d<=day[i] || step[j]+cp[j].k<=i) step[j]++; //为什么不用< <?因为t+d-1,所有为了满足条件,边界应该从某一天的最后一次
                dp[i]=min(dp[i],dp[step[j]-1]+cp[j].c);
            }
        }
        printf("%lld\n",dp[cnt]);
        return 0;
    }
    
posted @ 2021-09-11 18:09  Rayotaku  阅读(236)  评论(0编辑  收藏  举报