标签:处理 key 元素 node $set ali 随机选择 size i+1
对于每一个时间点,记录开始于此时间的红包和结束于此时间的红包
那么在$O(n)$的复杂度就可以处理出每一个时间点的红包
然后将这些红包插入$set$中,以$w$为第一关键字,$d$为第二关键字排序
每次取出$set$中最大元素即是当前父亲要选的红包
现在Alice会打扰其父亲,所以记$dp[i][j]$表示第$i$个时间点前,Alice打扰了$j$次时,父亲取到钱的最小值
那么对于这道题来说填表法比较复杂,所以考虑刷表法
对于一个时间点Alice可以选择打扰或不打扰
如果打扰,$dp[i][j]$可以转移到$dp[i+d][j$],$d$为当前选择红包的$d$值
如果不打扰,$dp[i][j]$可以转移到$dp[i+1][j+1]$
#include <bits/stdc++.h> #define ll long long #define inf 1e18 using namespace std; const ll MAXN=1e5+100; ll n,m,k,dp[MAXN][210],mt; struct node { ll s,t,d,w,key; }sh[MAXN]; vector <node> be[MAXN],ed[MAXN]; multiset <node> s;//需要用多重集合,考虑重复 bool operator < (node a,node b) { return (a.w>b.w || a.w==b.w && a.d>b.d || a.w==b.w && a.d==b.d && a.key<b.key); } int main() { srand(time(0)); scanf("%lld%lld%lld",&n,&m,&k); for (ll i=1;i<=k;i++) scanf("%lld%lld%lld%lld",&sh[i].s,&sh[i].t,&sh[i].d,&sh[i].w); for (ll i=1;i<=k;i++) sh[i].key=rand();//表示随机选择 for (ll i=1;i<=k;i++) { ed[sh[i].t].push_back(sh[i]); be[sh[i].s].push_back(sh[i]);//记录开始的红包和结束的红包 } for (ll i=1;i<=n+1;i++) { for (ll j=0;j<=m;j++) dp[i][j]=inf; } dp[1][0]=0;//初始打扰次数为0 for (ll i=1;i<=n;i++) { multiset <node> :: iterator it; for (ll j=0;j<(ll)ed[i-1].size();j++) { it=s.lower_bound(ed[i-1][j]); s.erase(it); } for (ll j=0;j<(ll)be[i].size();j++) s.insert(be[i][j]); if (s.empty()) { for (ll j=0;j<=min(i-1,m);j++) dp[i+1][j]=min(dp[i+1][j],dp[i][j]); } else { node g; g=*s.begin(); for (ll j=0;j<=min(i-1,m);j++) { if (j!=m)//注意边界 { dp[i+1][j+1]=min(dp[i+1][j+1],dp[i][j]); dp[g.d+1][j]=min(dp[g.d+1][j],dp[i][j]+g.w); } else { dp[g.d+1][j]=min(dp[g.d+1][j],dp[i][j]+g.w); } } } } ll ans=inf; for (ll i=0;i<=m;i++) ans=min(ans,dp[n+1][i]); printf("%lld\n",ans); }
CF1106E Lunar New Year and Red Envelopes
标签:处理 key 元素 node $set ali 随机选择 size i+1
原文地址:https://www.cnblogs.com/huangchenyan/p/11247364.html