Codeforces Round #536 (Div. 2) E. Lunar New Year and Red Envelopes(模拟+dp)

Description:

过年老爸去拿红包女儿要干扰他。有n个时间点,m次干扰机会,k个红包。每个红包有四个属性值s,t,d,w。

s和t分别是取红包的开始和结束时间,在这个时间外不能拿该红包。d是指若拿了该红包则在时间d之前都不能拿下一个红包,w是指红包的价值。

现在老爸在时间点1上只会贪心地去拿红包:1.每次会优先取当前能取得价值最大的红包2.若两红包都达到当前最大值,则选择d大的那个

女儿有m次机会干扰老爸,每次都在一个时间点上,可以使得老爸当前时刻无法拿任何红包。

问最后老爸最少能拿到多少钱。

Input:

n,m,k

si,ti,di,wi(for 1<=i<=k)

Output:

输出答案

Analysis:

考虑先模拟,求出爸爸在任何时刻的选择,因为这是女儿如何干扰都不会变得。具体来说是先把红包的开始和结束事件记录,然后按照事件的顺序,维护一个有序multiset,同时记录每个时刻的选择。

接下来直接dp就行, 设dp[i][j]表示,使用了i次干扰,到达了时刻j的获得的最少价值。状态转移方程为

              dp[i+1][j + 1] = min(dp[i+1][j + 1], dp[i][j]);
              dp[i][seq[j].d + 1] = min(dp[i][seq[j].d+1],dp[i][j]+seq[j].w);

学会了两点:1.用map<obj,num>做multiset 2.一种压缩空间写动态规划的方式

#define _CRT_SECURE_NO_WARNINGS  
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
#include<unordered_set>
#include<ctime>
#include<cstring>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
const int INF = 1 << 30;
const int maxn = 100005;
const int MOD = 1e9+7;
const double eps = 1e-6;

int n, m, k;
struct Event {
	int d, t, w;
	bool operator<(const Event & rhs)const {
		return w > rhs.w || (w == rhs.w&&d > rhs.d);
	}
	Event(int d,int t,int w):d(d),t(t),w(w) {}
	Event(){}
};
vector<Event> e[maxn],seq;
map<Event, int> cur;

LL dp[2][maxn];

void insert(Event x) {
	if (cur.count(x)) {
		cur[x]++;
	}
	else cur[x] = 1;
}
void erase(Event x) {
	cur[x]--;
	if(cur[x]==0) 
		cur.erase(x);
}

int main()
{
	//freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
	//freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);
	while (scanf("%d%d%d", &n, &m, &k)==3) {
		_rep(i, 1, n) {
			e[i].clear();
		}
		_for(i, 0, k) {
			int s, t, d, w;
			scanf("%d%d%d%d", &s, &t, &d, &w);
			e[s].push_back(Event(d, 1, w));
			e[t + 1].push_back(Event(d, -1, w));
		}
		cur.clear();
		seq.resize(n + 1);
		_rep(i, 1, n) {
			for (auto it :e[i] ) {
				if (it.t == 1)insert(it);
				else erase(it);
			}
			if (cur.size()) {
				seq[i] = (*cur.begin()).first;
			}
			else seq[i] = Event(i, 0, 0);
		}

		memset(dp, 0x3f3f3f3f3f3f3f3fLL, sizeof(dp));
		dp[0][1] = 0;
		LL ans = 0x3f3f3f3f3f3f3f3fLL;
		for (int i = 0; i <= m; ++i) {
			memset(dp[(i ^ 1) & 1], 0x3f3f3f3f3f3f3f3fLL, sizeof(dp[(i ^ 1)&1]));
			for (int j = 1; j <= n; ++j) {
				dp[(i ^ 1) & 1][j + 1] = min(dp[(i ^ 1) & 1][j + 1], dp[i & 1][j]);
				dp[i & 1][seq[j].d + 1] = min(dp[i & 1][seq[j].d+1],dp[i&1][j]+seq[j].w);
			}
			ans = min(ans, dp[i & 1][n + 1]);
		}
		cout << ans << endl;
	}
	

	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/tomandjake_/article/details/86933637