题目大意:
给定n m k;(1≤n≤1e5, 0≤m≤200, 1≤k≤1e5)
表示n个时间长度内 最多被打扰m次 k个红包
接下来k行描述红包 s t d w;(1≤s≤t≤d≤n , 1≤w≤1e9)
表示在 s 到 t 的时间内都可开始获得该红包
该红包在时间 d 时才能完成获得 红包内有w硬币
在同一时间段内只能获得一个红包 不能同时获得两个及以上
求在被打扰的情况下使获得的红包硬币最少 是多少
用in out标记各红包可被获得的区间
用multiset维护在某个时间点可获得的红包有哪些 (放入in内的 去掉out内的)
multiset内部按w排序 那么在某个时间点取出w最大的就是获得红包的贪心策略 .rbegin()可获得multiset/set内的最后一项
按时间点记忆化搜索一下 dp[ 时间点 ][ 被打扰次数 ]来记忆
以上存储信息要用pair<> 用结构体会MLE
#include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LL long long #define mem(i,j) memset(i,j,sizeof(i)) #define pb push_back #define mp(i,j) make_pair(i,j) #define fir first #define sec second #define P pair<LL,LL> const int N=1e5+5; P best[N]; // best[i] 在i位置的最佳策略 LL n, m, k; LL dp[N][205]; // 记忆化 dp[i][j]在i位置被打扰了j次能获得的最少硬币 multiset <P> now; // 维护当前位置所有能取的红包 pair默认按first排序 vector <P> in[N], out[N]; // in为从该位置开始可取的 out为从该位置开始不可取的 void init() { mem(dp,-1); now.clear(); for(int i=1;i<=n+1;i++) in[i].clear(), out[i].clear(); } LL DFS(int ind,int c) { if(ind>n) return 0LL; if(dp[ind][c]>=0LL) return dp[ind][c]; LL res=best[ind].fir+DFS(best[ind].sec+1,c); // 取这个红包 if(c<m) res=min(res,DFS(ind+1,c+1)); // 被女儿阻止 return dp[ind][c]=res; } int main() { while(~scanf("%d%d%d",&n,&m,&k)) { init(); for(int i=0;i<k;i++) { LL l,r,d,w; scanf("%I64d%I64d%I64d%I64d",&l,&r,&d,&w); in[l].pb(mp(w,d)); out[r+1].pb(mp(w,d)); } for(int i=1;i<=n+1;i++) { for(int j=0;j<in[i].size();j++) now.insert(in[i][j]); // 加入可取的 for(int j=0;j<out[i].size();j++) now.erase(now.find(out[i][j])); // 去掉不可取的 if(now.size()) best[i]=*now.rbegin(); // 最佳策略是w最大的 else best[i]={0LL,(LL)i}; } printf("%I64d\n",DFS(1,0)); } return 0; }
原文地址:https://www.cnblogs.com/zquzjx/p/10345461.html
时间: 2024-10-04 22:04:03