cff_0102
2024-11-18 08:56:31
刚开始看出来应该可以用 dp 了,但是因为某些原因没想到速度是可以放到状态里面的。
首先考虑
注意到全部数据范围的
但是这题空间卡的比较紧,即使用 double
也有 MLE 的可能,最好是把询问离线下来,再用滚动数组优化一下 dp,在 dp 过程中直接计算出所有询问的答案,就不需要把所有 dp 值存下来了。
既然都用滚动数组优化了,也不用担心空间的问题了,不如用精度更高的 long double
。
具体可以见代码注释。
#include<bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
const int N=1e5+5;
int pp[N],tt[N],xx[N];
double dp[2][32][21];
double p2[35],p3[25];
double ans[N];
pair<int,int>qu[N];
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
p2[0]=p3[0]=1;//预处理出 2 和 3 的幂次
for(int i=1;i<=32;i++)p2[i]=p2[i-1]*2;
for(int i=1;i<=23;i++)p3[i]=p3[i-1]*3;
int n,q;cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>pp[i]>>tt[i]>>xx[i];
}
for(int i=0;i<=1;i++)for(int j=0;j<=31;j++)for(int k=0;k<=20;k++)dp[i][j][k]=1e18;
dp[0][0][0]=0;//注意初始化
for(int i=1;i<=q;i++){
cin>>qu[i].first;qu[i].second=i;
}
sort(qu+1,qu+1+q);
int ppp=1;
for(int i=1;i<=n;i++){
double p=pp[i],t=tt[i],lp=pp[i-1];
int x=xx[i];
while(ppp<=q&&qu[ppp].first<p){//处理现在需要解决的所有询问(等一下这些要用到的 dp 值就滚走了)
double an=1e18;
for(int j=0;j<=31;j++){
for(int k=0;k<=20;k++){
an=min(an,dp[0][j][k]+(qu[ppp].first-lp)/p2[j]/p3[k]);//路程 / 速度 = 时间
}
}
ans[qu[ppp].second]=an;
ppp++;
}
for(int j=31;j>=0;j--){
for(int k=20;k>=0;k--){
dp[1][j][k]=dp[0][j][k]+(p-lp)/p2[j]/p3[k];//路程 / 速度 = 时间
}
}
for(int j=31;j>=0;j--){
for(int k=20;k>=0;k--){//注意这里的转移顺序
switch(x){
case 1:
break;//x=1,不用管
case 2:
if(j>0)dp[1][j][k]=min(dp[1][j][k],dp[1][j-1][k]+t);
break;//x=2,如果在这里加了油,那么原来的速度应该是 2^(j-1)*3^k
case 3:
if(k>0)dp[1][j][k]=min(dp[1][j][k],dp[1][j][k-1]+t);
break;//x=3,如果在这里加了油,那么原来的速度应该是 2^j*3^(k-1)
case 4:
if(j>1)dp[1][j][k]=min(dp[1][j][k],dp[1][j-2][k]+t);
break;//x=4,如果在这里加了油,那么原来的速度应该是 2^(j-2)*3^k
}
}
}
for(int j=31;j>=0;j--){
for(int k=20;k>=0;k--){
dp[0][j][k]=dp[1][j][k];
}
}
}
while(ppp<=q){//最后一个加油站右边的询问别忘了处理
double an=1e18;
for(int j=0;j<=31;j++){
for(int k=0;k<=20;k++){
an=min(an,dp[0][j][k]+(qu[ppp].first-pp[n])/p2[j]/p3[k]);
}
}
ans[qu[ppp].second]=an;
ppp++;
}
cout<<fixed<<setprecision(10);
for(int i=1;i<=q;i++)cout<<ans[i]<<"\n";
return 0;
}
要注意询问总数是 sort(qu+1,qu+1+n)
了,这样会挂成