题解:P12302 [ICPC 2023 WF] 时差
一道好题。
一个贪心的想法是,显然我会希望在某个活动结束后立即睡觉,这样我的可操作空间最大。但是这不行,因为如果活动结束的时刻落在
考虑一个关键点:如果我们现在在
所以我们只需要想办法让活动结束在这个阶段内就行。考虑一个结束在
于是我们得出结论:只要有方案,一定存在一种方案使得我必然总是在活动结束后睡觉。
考虑 dp。
于是转移是:
我们可以在 dp 过程中记录转移项,然后在最后往回构造。往回构造就是两个不等式,一个限制我们必须在活动结束时位于
于是我们获得了一个
int n;
int dp[N];
int lst[N];
ll b[N],e[N];
vector <pll> ans;
int main(){
#ifdef Shun
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
ios::sync_with_stdio(false);
cin>>n;
fr1(i,1,n) cin>>b[i]>>e[i];
dp[0]=1;
fr1(i,1,n){
fr2(j,i-1,0){
if(dp[j]&&(e[i]-e[j])<=3*(b[j+1]-e[j])){
lst[i]=j;
dp[i]=1;
break;
}
}
// cout<<dp[i]<<endl;
}
if(!dp[n]) cout<<"impossible\n";
else{
int x=n;
while(x){
int id=lst[x];
ll t=b[id+1]-e[id];
ll T=e[x]-e[id];
// cout<<t<<" "<<T<<endl;
ll k=(T+2)/3;
ans.push_back({e[id],e[id]+k});
x=lst[x];
}
reverse(ans.begin(),ans.end());
cout<<ans.size()<<'\n';
for(auto i:ans) cout<<i.fi<<" "<<i.se<<'\n';
}
ET;
}
//ALL FOR Zhang Junhao.
转移显然可以优化,移项之后形如
maxn=3*b[1];
fr1(i,1,n){
if(e[i]<=maxn) dp[i]=1,lst[i]=tf;
if(dp[i]){
ll coef=3*b[i+1]-2*e[i];
if(maxn<coef) maxn=coef,tf=i;
}
// cout<<dp[i]<<endl;
}
时间复杂度