1. 程式人生 > >Codeforces Round #536 E. Lunar New Year and Red Envelopes /// 貪心 記憶化搜索 multiset取最大項

Codeforces Round #536 E. Lunar New Year and Red Envelopes /// 貪心 記憶化搜索 multiset取最大項

find 去掉 close 分享 搜索 data- 技術分享 ace using

題目大意:

給定n m k;(1≤n≤1e5, 0≤m≤200, 1k1e5)

表示n個時間長度內 最多被打擾m次 k個紅包

接下來k行描述紅包 s t d w;(1stdn , 1w1e9)

表示在 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; }
View Code

Codeforces Round #536 E. Lunar New Year and Red Envelopes /// 貪心 記憶化搜索 multiset取最大項