CF1106E:multiset+dp

CF1106E

题解:

这一题有点麻烦,第一次用multiset。发现了神奇的erase让我一直WA,至今还是不懂。谁能告诉我orz!!!

  • 我们用dp[i][j]表示i时刻到n时刻用了j次阻拦,抢的最少红包。所以我们最后求min(dp[0][01…m]),发现了神奇的min_elemen函数。
  • 我们已知dp[n+1][01……m] = 0,所以从后往前推。
  • 用pair记录红包的价值w和d。开两个vector<pair<int,int>>S[N],T[N]来记录某个红包开始抢和截止的时间。如果红包在e1开始抢那么就在S[e1-1](因为e1还是可以抢的,e1-1就不能抢)里面塞入则个pair,e2截止就在T[e2]里面塞入pair。
  • 从后往前,所以在e2时刻塞T[e2]中的红包给multiset,到s[e1-1]就删除这个红包。
  • 状态转移方程如下:
  • 1、如果没有红包可以抢dp[i][j] = dp[i+1][j]
    2、如果有红包可以抢,并且不使用干扰,那么dp[i][j] = dp[i+1][j] + w;
    3、使用干扰,dp[i][j] = min(dp[i][j],dp[i+1][j-1]);

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int const N = 100000 + 10;
int const M = 200 + 10;
int const inf = 0x3f3f3f3f;
typedef pair<int,int>pii;
vector<pii> S[N],T[N];
multiset<pii>st;
int n,m,k;
ll dp[N][M];
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=k;i++){
		int s,t,d,w;
		scanf("%d%d%d%d",&s,&t,&d,&w);
		S[s-1].push_back(pii(w,d));   
		T[t].push_back(pii(w,d));
	}
	memset(dp[n+1],0,sizeof(dp[n+1]));
	for(int i=n;i;i--){
		for(int k=0;k<T[i].size();k++)	st.insert(T[i][k]);
		for(int k=0;k<S[i].size();k++)	st.erase(st.find(S[i][k]));    //注意要find,不能直接删除。
		if(st.empty())	for(int j=0;j<=m;j++)	dp[i][j] = dp[i+1][j];    //没有红包可以抢
		else{
			int w = st.rbegin()->first,	d = st.rbegin()->second;
			for(int j=0;j<=m;j++)	dp[i][j] = dp[d+1][j] + w;
			for(int j=1;j<=m;j++)	dp[i][j] = min(dp[i][j],dp[i+1][j-1]);
		}
	}
	printf("%lld\n",*min_element(dp[1],dp[1]+m+1));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42264485/article/details/87867083
今日推荐