題目連結: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 }