题解:P11986 [JOIST 2025] 救护车 / Ambulance
四个医院还是太复杂了,于是先弱化一下问题,将
设第
扩展到四个医院,还是按照刚刚的对角线划分。我们这次引入两个对角线序列,
枚举两个序列中的前后缀分界点,可以将所有点分成四组,每一组中的点可以前往两个地点。于是我们直接设计一个 dp,设
单次 dp 是
洛谷有点卡常,你开局就特判一下肯定无解的情况可以冲过去。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=170;
const int inf=1e9;
const int maxt=2e4+10;
void cmax(int &x,int y){ x=x>y?x:y; }
void cmin(int &x,int y){ x=x<y?x:y; }
struct node{ int x,y; }a[maxn]; int to[maxn];
int L,n,T,p[maxn],q[maxn],dp[4][maxn][maxt];
int c1(int id){ return a[id].x+a[id].y-2; }
int c2(int id){ return a[id].x-1+L-a[id].y; }
int c3(int id){ return L-a[id].x+a[id].y-1; }
int c4(int id){ return L-a[id].x+L-a[id].y; }
bool cmp(int x,int y){ return c1(x)<c1(y); }
bool cmp2(int x,int y){ return c2(x)<c2(y); }
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin>>L>>n>>T; T/=2; bool flag=1; int co=T;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y;
cmin(co,c1(i)); cmin(co,c2(i));
cmin(co,c3(i)); cmin(co,c4(i));
flag&=(a[i].x==a[1].x&&a[i].y==a[1].y);
}
if(n/4*co>T){ cout<<"No"; return 0; }
for(int i=1;i<=n;i++) p[i]=i,q[i]=i,to[i]=4;
sort(p+1,p+1+n,cmp); sort(q+1,q+1+n,cmp2);
for(int i=0;i<=n;i++){//[1,i]->1 [i+1,n]->4
//[1,j]->2 [j+1,n]->3
for(int j=1;j<=n;j++){
int u=q[j];
for(int t=0;t<=T;t++){
if(to[u]==1){
dp[2][j][t]=dp[2][j-1][t];
dp[0][j][t]=dp[0][j-1][t]+c2(u);
if(c1(u)<=t) cmin(dp[0][j][t],dp[0][j-1][t-c1(u)]);
if(t) cmin(dp[0][j][t],dp[0][j][t-1]);
}else{
dp[0][j][t]=dp[0][j-1][t];
dp[2][j][t]=dp[2][j-1][t]+c2(u);
if(c4(u)<=t) cmin(dp[2][j][t],dp[2][j-1][t-c4(u)]);
if(t) cmin(dp[2][j][t],dp[2][j][t-1]);
}
}
}
for(int j=n-1;j>=0;j--){
int u=q[j+1];
for(int t=0;t<=T;t++){
if(to[u]==1){
dp[3][j][t]=dp[3][j+1][t];
dp[1][j][t]=dp[1][j+1][t]+c3(u);
if(c1(u)<=t) cmin(dp[1][j][t],dp[1][j+1][t-c1(u)]);
if(t) cmin(dp[1][j][t],dp[1][j][t-1]);
}else{
dp[1][j][t]=dp[1][j+1][t];
dp[3][j][t]=dp[3][j+1][t]+c3(u);
if(c4(u)<=t) cmin(dp[3][j][t],dp[3][j+1][t-c4(u)]);
if(t) cmin(dp[3][j][t],dp[3][j][t-1]);
}
}
}
for(int j=0;j<=n;j++){
int z=T;
for(int t1=0;t1<=T;t1++){//枚举 (1,1)
int t2=dp[0][j][t1],t3=dp[1][j][T-t1];
if(max(t2,t3)>T) continue;
t2=T-t2; t3=T-t3;
if(dp[2][j][z]>t2) continue;
while(z&&dp[2][j][z-1]<=t2) z--;
if(dp[3][j][T-z]<=t3){ cout<<"Yes"; return 0; }
}
}
to[p[i+1]]=1;
}
cout<<"No";
return 0;
}