题目链接:http://acm.nefu.edu.cn/contestShow.php
比赛的时候没写出来的题,想着建树深搜一下,无奈TLE又MLE(QAQ),再看题解,原来正解是DP。%%%%
题目大意:
在老爷机上玩游戏,每天有固定的时间,每款游戏有固定的开始和结束时间,不能中途离开游戏,也不能在游戏中途开始游戏,并且空闲的时候有游戏开始就必须玩。有游玩时间最长与游玩时间最短两种策略,一天选择了一种,下一天必须选择另一种,并且要尽可能地玩,问老爷机又多长时间是不被玩的。
解题思路:
首先看到这题可能会想到贪心,但是其实贪心并不可以废话为什么呢,因为每次空闲的时候有游戏开始的话,必须选择一个游戏玩,这样就导致此刻的选择具有后效性,这样的话贪心就不适用了。所以我们要用DP,但是这里要注意的是要逆推而不能正推,因为之前的选择会对之后产生影响,但是之后并不会对之前产生影响。题目要求老爷机的空闲时间,那我们就设dp[i]为从 i~n+1 的空闲时间,如果此刻空闲,转移方程为 dp[i]=dp[i+1]+1。如果此刻有游戏开始,转移方程dp1[i]=max(dp1[i],dp1[a[k].r])与dp2[i]=min(dp2[i],dp2[a[k].r]);
最后输出 4dp2[1]+3dp1[1]。
完整AC代码:
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn=1e5+5;
struct node
{
int l,r;
}a[maxn];
int cnt[maxn];
int dp1[maxn];
int dp2[maxn];
bool cmp(node p,node q)
{
if(p.l==q.l)
return p.r>q.r;
return p.l>q.l;
}
int main()
{
int t,n;
scanf("%d %d",&t,&n);
for(int i=1;i<=n;i++)
{
scanf("%d %d",&a[i].l,&a[i].r);
cnt[a[i].l]++;
}
sort(a+1,a+1+n,cmp);
int k=1;
for(int i=t;i>=1;i--)
{
if(!cnt[i])
{
dp1[i]=dp1[i+1]+1;
dp2[i]=dp2[i+1]+1;
}
else
{
dp1[i]=dp1[a[k].r];
dp2[i]=dp2[a[k++].r];
for(int j=1;j<cnt[i];j++)
{
dp1[i]=max(dp1[i],dp1[a[k].r]);
dp2[i]=min(dp2[i],dp2[a[k++].r]);
}
}
}
printf("%d\n",4*dp2[1]+3*dp1[1]);
return 0;
}