题目链接:http://codeforces.com/contest/158/problem/E
题意:给出一些电话,有打进来的时间和持续的时间,如果人在打电话,那么新打进来的电话入队,如果人没有打电话,那么人必须立即接电话,或者选择一次放弃的机会,问这个最多有多长的连续的空闲的时间。
题解:按照套路最长一般都是依靠dp来求解或者贪心。然后由于数据也就4000所以不难想到设
dp[i][j]表示处理到第i个电话时,无视了j个电话之后最短的结束时间,于是转移方程如下:
dp[i][j] = min(dp[i - 1][j - 1] , max(dp[i - 1][j] , t[i] - 1) + d[i]);要么就无视当前电话,
要么接听当前电话。
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int M = 4e3 + 10; int t[M] , d[M] , dp[M][M]; int main() { int n , k; scanf("%d%d" , &n , &k); for(int i = 1 ; i <= n ; i++) { scanf("%d%d" , &t[i] , &d[i]); } dp[0][0] = 0; for(int i = 1 ; i <= n ; i++) { dp[i][0] = max(t[i] - 1 , dp[i - 1][0]) + d[i]; for(int j = 1 ; j <= k && j <= i ; j++) { dp[i][j] = min(dp[i - 1][j - 1] , max(dp[i - 1][j] , t[i] - 1) + d[i]); } } int ans = t[1] - 1; for(int i = 1 ; i <= n ; i++) { for(int j = 0 ; j <= k && j < i ; j++) { ans = max(ans , t[i] - dp[i - 1][j] - 1); } } for(int j = 0 ; j <= k ; j++) { ans = max(ans , 86400 - dp[n][j]); } printf("%d " , ans); return 0; }