Codeforces 721E DP

大概思路及题意看这篇博客

我的理解:设f[i]表示处理到第i个区间,能唱的最多的歌,g[i]是保证f[i]最大时最靠左的点。那么f[i] = max(f[j] + (r[i] - max(l[i], g[j] + t)) / p), g[i] = r[i] - (r[i] - max(l[i], g[j] + t)) % p);容易发现, f[i]和g[i]是单增的,所以有很多状态是不可能转移的。只有在两个位置之间的状态才有可能更新状态。1:g[j] + t <= [i]的最大的j。2:g[j] + t <= r[i]的最大的j。在这之间的状态有可能会对状态产生影响,我们需要一个个出队,去更新状态,这样有很多的状态出队了,大大降低了时间复杂度。需要注意,第二个位置的状态在出队之后还需要入队,因为它可能成为i + 1状态的1位置。

代码:

#include <bits/stdc++.h>
#define pii pair<int, int>
using namespace std;
const int maxn = 100010;
int f[maxn], g[maxn];
int q[maxn];
pii a[maxn];
int main() {
	int L, n, p, t;
	scanf("%d%d%d%d", &L, &n, &p, &t);
	for (int i = 1; i <= n; i++)
		scanf("%d%d", &a[i].first, &a[i].second);
	int l = 1, r = 0;
	g[0] = -t;
	for (int i = 1; i <= n; i++) {
		f[i] = f[i - 1];
		g[i] = g[i - 1];
		l--;
		while(l <= r && g[q[l]] + t <= a[i].second) {
			int x = max(a[i].first, g[q[l]] + t);
			int y = f[q[l]] + (a[i].second - x) / p;
			int z = a[i].second - (a[i].second - x) % p;
			if(y > f[i] || (y == f[i] && g[i] > z)) {
				f[i] = y;
				g[i] = z;
			}
			l++;
		}
		q[++r] = i;
	}
	printf("%d
", f[n]);
} 

  

原文地址:https://www.cnblogs.com/pkgunboat/p/10759678.html