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; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮