题解:P10432 [JOISC 2024 Day1] 滑雪 2
喵喵喵,性质题。
首先是一个最基本的观察:
性质
1 :对于同一个点,不可能既抬高海拔,又加装新的连接设施。
考虑反证:不妨设
性质
2 :存在一种最优策略,使得每一个高度上都至少有1 个点不被抬高,且这个点一定是该高度上C 最小的点。
首先,我们显然不可能抬高所有点,让该高度空置。其次,若有若干个点被抬高到当前高度,则不难发现,保留原来就在这个高度的点一定更优,因为他们都会为更高的位置提供
此时可以开始考虑 dp。我们按高度从低到高扫描,设
-
不妨首先将高度
i+1 处的cnt_{i+1} 个点和j 合并,得到的新状态是dp_{i+1,j,k+cnt_{i+1}} ,代价是k\times K 。 -
枚举连到现有接口的点数
x\leq j ,得到的新状态是dp_{i+1,j,k+cnt_{i+1}-x} ,代价不变。 -
枚举在前面新增接口的点数
y\leq k+cnt_{i+1}-x ,得到的新状态是dp_{i+1,j+y,k+cnt_{i+1}-x-y} 。设minc_i 表示高度i 及之前的所有点中最小的C ,根据性质1 和性质2 ,不难得出此步的代价为y\times minc_i 。
综上,我们对每个状态枚举
性质
3 :每一个高度都一定会尽可能用完上一个高度留下来的所有j 个免费设施。
原因很显然:使用一个免费设施后,自己也会产生一个新的免费设施位置,不会使得免费位置减少,所以能用就用。因此
还可以发现的是,
最后一步显然是离散化高度。考虑哪些高度是有效的。
性质
4 :有效的高度是不增加任何额外设施,仅将所有点在高度上往后排开,每个高度安排一个点,得到的所有有点的高度。
这些高度显然是必要的,它们对应只增加海拔而不新建设施的方案。充分的原因是,根据性质
此时,我们可以将所有有效高度离散化至
需要注意的是,转移中
#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define repp(i,j,k) for(int i=j;i>=k;i--)
#define ls(x) (x<<1)
#define rs(x) ((x<<1)|1)
#define mp make_pair
#define sec second
#define fir first
#define pii pair<int,int>
#define lowbit(i) i&-i
#define int long long
#define qingbai 666
using namespace std;
typedef long long ll;
const int N=305,M=105,inf=(ll)1e18+7,mo=998244353;
void read(int &p){
int x=0,w=1;
char ch=0;
while(!isdigit(ch)){
if(ch=='-')w=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
p=x*w;
}
int upp=(ll)1e12;
int n,co,h[N],lsh[N],cntl,c[N];
int dp[N][N][N],minc[N],cntp[N],sumc[N];
signed main(){
read(n),read(co);
rep(i,1,n)
read(h[i]),read(c[i]),lsh[++cntl]=h[i];
sort(lsh+1,lsh+cntl+1);
rep(i,2,cntl)
lsh[i]=max(lsh[i],lsh[i-1]+1);//离散化,将点铺开
rep(i,1,n)
h[i]=lower_bound(lsh+1,lsh+cntl+1,h[i])-lsh;
rep(i,1,cntl)
minc[i]=inf;
rep(i,1,n)
cntp[h[i]]++,minc[h[i]]=min(minc[h[i]],c[i]);
minc[0]=inf;
rep(i,1,cntl)
minc[i]=min(minc[i],minc[i-1]),sumc[i]=sumc[i-1]+cntp[i];
rep(i,0,cntl){
rep(j,0,n+2){
rep(k,0,n+2)
dp[i][j][k]=upp;
}
}
dp[1][1][cntp[1]-1]=0;
rep(i,1,cntl-1){
rep(j,0,n){
repp(k,max(0ll,sumc[i]-1),0){
int nk=k+cntp[i+1],niv;
if(k&&(lsh[i+1]-lsh[i])*co>upp)niv=upp+1;
else niv=k*(lsh[i+1]-lsh[i])*co;
if(!i)nk--;
if(nk<=j)dp[i+1][j][0]=min(dp[i+1][j][0],dp[i][j][k]+niv);
else{
dp[i+1][j][nk-j]=min(dp[i+1][j][nk-j],dp[i][j][k]+niv);
dp[i+1][j+1][nk-j-1]=min(dp[i+1][j+1][nk-j-1],dp[i+1][j][nk-j]+minc[i]);
}
}
}
}
int ans=inf;
rep(j,0,n)
ans=min(ans,dp[cntl][j][0]);
printf("%lld\n",ans);
return 0;
}