Codeforces 158E Phone Talks:dp
题目链接: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 }