VK Cup 2012 Qualification Round 1 E. Phone Talks —— DP

来源:互联网 发布:淘宝网花卉 编辑:程序博客网 时间:2024/04/29 15:42

题目链接:http://codeforces.com/contest/158/problem/E


E. Phone Talks
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Cool J has recently become a businessman Mr. Jackson, and he has to make a lot of phone calls now. Today he has n calls planned. For each call we know the moment ti (in seconds since the start of the day) when it is scheduled to start and its duration di (in seconds). All ti are different. Mr. Jackson is a very important person, so he never dials anybody himself, all calls will be incoming.

Mr. Jackson isn't Caesar and he can't do several things at once. If somebody calls him while he hasn't finished the previous conversation, Mr. Jackson puts the new call on hold in the queue. In this case immediately after the end of the current call Mr. Jackson takes the earliest incoming call from the queue and starts the conversation. If Mr. Jackson started the call at the second t, and the call continues for d seconds, then Mr. Jackson is busy at seconds t, t + 1, ..., t + d - 1, and he can start a new call at second t + d. Note that if Mr. Jackson is not busy talking when somebody calls, he can't put this call on hold.

Mr. Jackson isn't Napoleon either, he likes to sleep. So sometimes he allows himself the luxury of ignoring a call, as if it never was scheduled. He can ignore at most k calls. Note that a call which comes while he is busy talking can be ignored as well.

What is the maximum number of seconds Mr. Jackson can sleep today, assuming that he can choose an arbitrary continuous time segment from the current day (that is, with seconds from the 1-st to the 86400-th, inclusive) when he is not busy talking?

Note that some calls can be continued or postponed to the next day or even later. However, the interval for sleep should be completely within the current day.

Input

The first input line contains a pair of integers nk (0 ≤ k ≤ n ≤ 4000) separated by a space. Following n lines contain the description of calls for today. The description of each call is located on the single line and consists of two space-separated integers ti and di, (1 ≤ ti, di ≤ 86400). All ti are distinct, the calls are given in the order of strict increasing ti.

Scheduled times of calls [titi + di - 1] can arbitrarily intersect.

Output

Print a number from 0 to 86400, inclusive — the maximally possible number of seconds for Mr. Jackson to sleep today.

Examples
input
3 230000 1500040000 1500050000 15000
output
49999
input
5 11 2000010000 1000020000 2000025000 1000080000 60000
output
39999
Note

In the first sample the most convenient way is to ignore the first two calls.

In the second sample it is best to ignore the third call. In this case Mr. Jackson will have been speaking:

  • first call: from 1-st to 20000-th second,
  • second call: from 20001-st to 30000-th second,
  • fourth call: from 30001-st to 40000-th second (the third call is ignored),
  • fifth call: from 80000-th to 139999-th second.

Thus, the longest period of free time is from the 40001-th to the 79999-th second.




题解:

一开始以为是前缀和+后缀和就能解决的,结果发现接电话的时间不是固定的(如果跳过了前面的电话),所以行不通。

再后来看看n的大小:4e3。O(n^2)也不会超时,于是就试一下用DP。

设dp[i][j]为操作到第i个电话,跳过了 j个电话的状态下的最大休息时间。

然而:怎么找最大休息时间呢?还有:状态怎么转移呢?所以这种方法行不通。


正确做法:

1.设dp[i][j]为操作到第i个电话,跳过了j个电话的状态下的最小用时。

2.那么对于当前这个电话来说,就有跳过和不跳过两种选择,

跳过:则dp[i][j] = dp[i-1][j-1]

接通:则dp[i][j] = max(dp[i-1][j], t[i]-1) + d[i]。

两者取其小,则: dp[i][j] = min( dp[i-1][j-1],  max(dp[i-1][j], t[i]-1) + d[i]  )

当然,对于j==0时(即所有电话都接通), 直接计算即可: dp[i][0] = max(t[i]-1, dp[i-1][0]) + d[i]

3.最后:可知跳过的电话越多,休息时间可能越大,那么就直接取跳过k个电话。然后枚举每个电话与跳过之前k个电话后的时间间隔,取最大。



反思:

当初设置的状态:dp[i][j]为操作到第i个电话,跳过了j个电话的状态下的最大休息时间。

本想着递推到最后的dp[n][k]就是答案(想着一步登天),奈何此种状态找不到相关的转移方程。

看了题解后发现答案分两步求出:1.先求最小结束时间,2.再求最大间隔。

所以:不要总认为答案能一步求出,很可能要经过多步操作。尤其是DP: dp[n]不一定就是最终答案,或许还要经过几步操作方可得出。



代码如下:

#include<bits/stdc++.h>  using namespace std;  typedef long long LL;  const double eps = 1e-6;  const int INF = 2e9;  const LL LNF = 9e18;  const int mod = 1e9+7;  const int maxn = 4e3+10;    int n,k;  int t[maxn], d[maxn], dp[maxn][maxn];    int main()  {      scanf("%d%d",&n,&k);      for(int i = 1; i<=n; i++)          scanf("%d%d",&t[i], &d[i]);    //    for(int i = 0; i<=n; i++)   //表明删除的电话>=实际电话时,结束时刻为0//    for(int j = i; j<=n; j++)//        dp[i][j] = 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<=min(i,k); j++)               dp[i][j] = min( dp[i-1][j-1], max(dp[i-1][j],t[i]-1)+d[i] );      }        int ans = 0;      t[++n] = 86400+1;      for(int i = 1; i<=n; i++)            ans = max( ans, t[i]-dp[i-1][min(i-1,k)]-1 );      cout<<ans<<endl;  } 


阅读全文
0 0