CF553E Kyoya and Train
Kyoya and Train
一个有n个节点m条边的有向图,每条边连接了ai和bi,花费为ci。
每次经过某一条边就要花费该边的ci。
第i条边耗时为j的概率为pi,j。
现在你从1开始走到n,如果你在t单位时间内(包括t)到了n,不需要任何额外花费,否则你要额外花费x。
问你在最优策略下的期望花费最小为多少。(注意你每走一步都会根据当前情况制定最好的下一步)
n≤50,m≤100,t≤20000,x≤106
毛啸论文
看别人的代码,我学会了怎么用线性的空间预处理单位根。
2π2step×i=2πlim×lim2step×i
而lim2step×i<lim2,i∈[0,step),所以预处理ω2πlim的次幂即可。
co double pi=acos(-1); struct node {double x,y;}; il node operator+(co node&a,co node&b){ return (node){a.x+b.x,a.y+b.y}; } il node operator-(co node&a,co node&b){ return (node){a.x-b.x,a.y-b.y}; } il node operator*(co node&a,co node&b){ return (node){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x}; } co int N=55,M=105,T=20005,S=1<<15; int n,m,t,punish; int a[M],b[M],c[M],dis[N][N]; double dp[N][T],sum[M][T],p[M][T]; int rev[S]; node w[S],A[S],B[S]; void fourier_trans(node a[],int lim){ for(int i=0;i<lim;++i) if(i<rev[i]) swap(a[i],a[rev[i]]); for(int step=1;step<lim;step<<=1){ int quot=lim/(step<<1); for(int i=0;i<lim;i+=step<<1){ int j=i+step; for(int k=0;k<step;++k){ node t=w[quot*k]*a[j+k]; a[j+k]=a[i+k]-t,a[i+k]=a[i+k]+t; } } } } void solve(int l,int r){ if(l==r){ for(int e=1;e<=m;++e) dp[a[e]][l]=min(dp[a[e]][l],sum[e][l]+c[e]); return; } int mid=(l+r)>>1; solve(mid+1,r); int len=int(ceil(log2(r-mid+r-l-1))),lim=1<<len; for(int i=0;i<lim;++i){ rev[i]=rev[i>>1]>>1|(i&1)<<(len-1); w[i]=(node){cos(i*2*pi/lim),sin(i*2*pi/lim)}; } for(int e=1;e<=m;++e){ for(int i=0;i<lim;++i) A[i]=B[i]=(node){0,0}; for(int i=mid+1;i<=r;++i) A[i-mid-1]=(node){dp[b[e]][i],0}; for(int i=1;i<=r-l;++i) B[r-l-i]=(node){p[e][i],0}; fourier_trans(A,lim),fourier_trans(B,lim); for(int i=0;i<lim;++i){ A[i]=A[i]*B[i]; w[i].y=-w[i].y; } fourier_trans(A,lim); for(int i=0;i<lim;++i){ A[i].x/=lim; w[i].y=-w[i].y; } for(int i=l;i<=mid;++i) sum[e][i]+=A[i-mid-1+r-l].x; } solve(l,mid); } int main(){ scanf("%d%d%d%d",&n,&m,&t,&punish); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) dis[i][j]=i==j?0:1e9; for(int i=1;i<=m;++i){ scanf("%d%d%d",a+i,b+i,c+i); dis[a[i]][b[i]]=min(dis[a[i]][b[i]],c[i]); for(int j=1;j<=t;++j) scanf("%lf",p[i]+j),p[i][j]/=100000; } for(int k=1;k<=n;++k) for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); for(int i=0;i<N;++i) for(int j=0;j<T;++j) dp[i][j]=1e9; for(int i=1;i<=n;++i) dp[i][t+1]=punish+dis[i][n]; for(int i=0;i<=t;++i) dp[n][i]=0; for(int e=1;e<=m;++e){ double P=0; for(int i=1;i<=t;++i){ P+=p[e][t+1-i]; sum[e][i]=P*dp[b[e]][t+1]; } } solve(0,t); printf("%lf\n",dp[1][0]); return 0; }
静渊以有谋,疏通而知事。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构