Codeforces 158E Phone Talks:dp

Leohh發表於2018-01-11

題目連結:http://codeforces.com/problemset/problem/158/E

題意:

  你有n個電話要接,每個電話打進來的時刻為第t[i]分鐘,時長為d[i]分鐘。

  每一個電話打進來時,你有兩種選擇:

    將電話掛掉,或接聽(如果當時正在打其他電話,則這個電話加入等待佇列,等上一個電話打完後立馬接聽)

  你最多能掛掉k個電話。

  時間從第1分鐘開始算,一直到86400分鐘結束,問你能夠獲得的最長連續間隔為多長時間。

 

題解:

  表示狀態:

    dp[i][j] = clocks

    表示打了前i個電話,掛掉了其中j個電話,打完這些電話的最早時刻。

 

  找出答案:

    有一個貪心結論,就是這k次掛電話的機會必須用完。

    特別地,t[n+1] = 86401。

    ans = min t[i+1]-dp[i][k]-1

 

  如何轉移:

    dp[i][j] = min( max(dp[i-1][j]+d[i],t[i]+d[i]-1), dp[i-1][j-1] )

    對於第i個電話,要麼接,要麼不接。

    如果接,則第i個電話開始的時刻為max(dp[i-1][j]+1, t[i]),所以結束時刻為max(dp[i-1][j]+d[i],t[i]+d[i]-1)。

    如果不接,則最後時刻還是dp[i-1][j-1]。

 

  邊界條件:

    dp[0][0] = 0

    others = INF

    另外,當n == 0時要特判,直接輸出86400即可。

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX_N 4005
 5 #define MAX_K 4005
 6 
 7 using namespace std;
 8 
 9 int n,k;
10 int t[MAX_N];
11 int d[MAX_N];
12 int dp[MAX_N][MAX_K];
13 
14 void read()
15 {
16     cin>>n>>k;
17     for(int i=1;i<=n;i++)
18     {
19         cin>>t[i]>>d[i];
20     }
21     t[n+1]=86401;
22 }
23 
24 void work()
25 {
26     if(n==0)
27     {
28         cout<<"86400"<<endl;
29         return;
30     }
31     memset(dp,0x3f,sizeof(dp));
32     dp[0][0]=0;
33     for(int i=1;i<=n;i++)
34     {
35         for(int j=0;j<=min(i,k);j++)
36         {
37             dp[i][j]=max(dp[i-1][j]+d[i],t[i]+d[i]-1);
38             if(j>0) dp[i][j]=min(dp[i][j],dp[i-1][j-1]);
39         }
40     }
41     int ans=0;
42     for(int i=1;i<=n;i++)
43     {
44         ans=max(ans,t[i+1]-dp[i][k]-1);
45     }
46     cout<<ans<<endl;
47 }
48 
49 int main()
50 {
51     read();
52     work();
53 }

 

相關文章