1 条题解
-
0
四个医院还是太复杂了,于是先弱化一下问题,将 个医院变成 个,且两个医院处于对角线。
设第 个人到医院 的代价为 ,到医院 的代价为 。可以发现 为一个定值,于是就是一个经典贪心,直接按照 排序后,前缀分配给医院 ,后缀分配给医院 。
扩展到四个医院,还是按照刚刚的对角线划分。我们这次引入两个对角线序列, 和 一组, 和 一组。对于第一组按照到 的距离排序,对于第二组按照到 的距离排序。
枚举两个序列中的前后缀分界点,可以将所有点分成四组,每一组中的点可以前往两个地点。于是我们直接设计一个 dp,设 表示考虑了这一组的中的前 个元素,第一个医院用时为 的时候,第二个医院的最小用时。对于四组分别 dp 之后,枚举 的用时,然后利用第一组和第二组的 dp 信息可以得到到 和到 的最小用时,利用第三组的 dp 信息可以得到 的最小用时,再利用第四组的 dp 信息判定 和 当前的用时是否合法即可。
单次 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; }
- 1
信息
- ID
- 8376
- 时间
- 2000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者