ThisIsLu
2024-11-17 17:42:19
看到题目,不难想到朴素 dp:
令
转移:
但是可能的速度太多了,所以此 dp 是指数级的。
我们注意到,当速度过大时,时间耗费近似为
而题目中有这么一句话:
所以,如果速度为
而
但我们还要一个状态来表示速度过快,所以一共有
具体实现上,如果使用 umap 或 map 来存储状态,会爆空间或时间,所以要对这
对于查询,二分出距离最远且在
最后请注意不要用 float
,精度不够;也不要用 long double
,会快乐的 MLE。
code:
#include<bits/stdc++.h>
using namespace std;
int s[32]={0,50,99,146,192,236,278,319,358,396,432,466,499,530,560,588,615,640,663,685,705,724,741,756,770,782,793,802,810,816,820,823},a[32]={50,49,47,46,44,42,41,39,38,36,34,33,31,30,28,27,25,23,22,20,19,17,15,14,12,11,9,8,6,4,3,1};
long long powb[32]={1,3,9,27,81,243,729,2187,6561,19683,59049,177147,531441,1594323,4782969,14348907,43046721,129140163,387420489,1162261467,3486784401,10460353203,31381059609,94143178827,282429536481,847288609443,2541865828329,7625597484987,22876792454961,68630377364883,205891132094649,617673396283947};
int n,q;
const int N=1e5;
int p[N+5],t[N+5],x[N+5];
double dp[N+5][825];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int tmp;
cin>>tmp>>q;
for(int i=1;i<=tmp;i++){
int pi,ti,xi;
cin>>pi>>ti>>xi;
if(xi==1) continue;
p[++n]=pi;
t[n]=ti;
x[n]=xi;
}
for(int i=1;i<825;i++) dp[0][i]=1e18;
for(int i=0;i<n;i++){
dp[i+1][824]=dp[i][824];
for(int j=31;j>=0;j--){
for(int k=a[j]-1;k>=0;k--){
int pos;
if(x[i+1]==2) pos=(k==a[j]-1?824:s[j]+k+1);
else if(x[i+1]==3) pos=(j==31?824:s[j+1]+k);
else pos=(k>=a[j]-2?824:s[j]+k+2);
dp[i+1][pos]=min(dp[i+1][pos],dp[i][s[j]+k]+(double)(p[i+1]-p[i])/(powb[j]<<k)+t[i+1]);
dp[i+1][s[j]+k]=dp[i][s[j]+k]+(double)(p[i+1]-p[i])/(powb[j]<<k);
}
}
}
for(int i=1;i<=q;i++){
int y;
cin>>y;
int pos=upper_bound(p+1,p+n+1,y)-p-1;
double ans=dp[pos][824];
for(int j=31;j>=0;j--){
for(int k=0;k<a[j];k++){
ans=min(ans,dp[pos][s[j]+k]+(double)(y-p[pos])/(powb[j]<<k));
}
}
cout<<fixed<<setprecision(9)<<ans<<"\n";
}
return 0;
}