题目大意

链接:CF533E

给一张\(n\)个点,\(m\)条边的图,起点\(1\)终点\(n\),如果不能在\(T\)的时间内到达则需支付\(X\)的代价。

走每条边都会支付一定代价,经过一条边\(i\)的时间有\(p_{i,j}\)的概率为\(j\),最小化期望代价。

题目分析

暴力方法:期望DP

设\(f_{i,j}\)表示在第\(j\)时刻,从\(i\)点出发,到达终点的期望花费,

设边为\(e\),边上两点为\(x,y\),边集为\(E\),则有

\[f(x,t)=\min\limits_{e\in E}\{val_{e}+\sum_{i=1}^Tp_{e,i}\cdot f(y,t+i)\}
\]

时间复杂度\(O(n\cdot T^2)\)。

或许你会觉得这样转移有问题,因为这不是一个DAG图,

但是,由于没有负权环,一个点不可能回到它的祖先,所以我们可以当做DAG来处理。


现在想想怎么优化这个DP。

我们设\(g_{e,t}\)表示\(\sum\limits_{i=1}^Tp_{e,i}\cdot f(y,t+i)\),显然有

\[f(x,t)=\min\{val_e+g(e,t)\}
\]

我们可以利用分治。

如果要求出\(l\leq t\leq r\)的所有\(f(x,t)\)和\(g(e,t)\),不妨设\(mid=l+r>>1\),

先求出\(mid<t\leq r\)的\(f\),并用这些\(f\)去更新\(l\leq t\leq mid\)的\(g\),然后递归下去即可。


(方法co自这位大佬的博客)

对于\(g(e,t)\),我们可以考虑把它化为卷积的形式进行更新。

令\(mid=mid+1\),对于\(g(e,mid-1)\),我们有\(g(e,mid-1)+=\sum\limits_{i=0}^{r-mid+1}p_{e,i+1}\cdot f(e,mid+i)\)

我们把\(f\)数组反转,\(g(e,mid-1)+=\sum\limits_{i=0}^{r-mid+1}p_{e,i+1}\cdot f(e,r-i)\)。

在映射一下:\(g(e,mid-1)+=\sum\limits_{i=0}^{r-mid+1}p^{\prime}_{e,i}\cdot f^\prime(e,r-mid-i)\)。

即:\(g(e,mid-x)+=\sum\limits_{i=0}^{r-mid+1}p^{\prime}_{e,i}\cdot f^\prime(e,r-(mid-x)-i-1)\)

用\(ans(r-(mid-x)-1)\)来更新\(g(mid-x)\),即用\(ans(r-t-1)\)来更新\(g(t)\)。

代码实现

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#define MAXN 1<<30
typedef long long LL;
const int N=100005;
using namespace std;
inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;} const double pi=acos(-1);
struct Z{
double r,i;
Z(double _r=0,double _i=0){r=_r,i=_i;}
Z operator + (const Z &a)const{return Z(r+a.r,i+a.i);}
Z operator - (const Z &a)const{return Z(r-a.r,i-a.i);}
Z operator * (const Z &a)const{return Z(r*a.r-i*a.i,r*a.i+i*a.r);}
Z operator / (const double &a)const{return Z(r/a,i/a);}
Z operator /= (const double &a) {return *this=Z(r/a,i/a);}
};
void FFT(Z *a,int x,int K){
static int rev[N],lst;
int n=1<<x;
if(n!=lst){
for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<x-1);
lst=n;
}
for(int i=0;i<n;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
for(int i=1;i<n;i<<=1){
int tmp=i<<1;
Z wn(cos(pi/i),sin(pi*K/i));
for(int j=0;j<n;j+=tmp){
Z w(1,0);
for(int k=0;k<i;k++,w=w*wn){
Z x=a[j+k],y=w*a[i+j+k];
a[j+k]=x+y,a[i+j+k]=x-y;
}
}
}
if(K==-1)for(int i=0;i<n;i++)a[i]/=n;
}
Z a[N],b[N]; int n,m,T,X;
double p[105][20005];
struct node{int x,y,z;}s[105];
double mp[55][55],f[55][N],g[105][N];
void Floyd(){
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
}
void Cal(int l,int mid,int r){
int len=r-l;
for(int j=1;j<=m;j++){
int x=ceil(log2(len+r-mid));
fill(a,a+(1<<x),0),fill(b,b+(1<<x),0);
for(int i=0;i<r-mid+1;i++)a[i].r=f[s[j].y][r-i];
for(int i=0,lim=min(T,len);i<lim;i++)b[i].r=p[j][i+1];
FFT(a,x,1),FFT(b,x,1);
for(int i=0;i<(1<<x);i++)a[i]=a[i]*b[i];
FFT(a,x,-1);
for(int i=mid-1;i>=l;i--)g[j][i]+=a[r-i-1].r;
}
}
void Binary(int l,int r){
if(l==r){
for(int i=1;i<=m;i++)
f[s[i].x][l]=min(f[s[i].x][l],s[i].z+g[i][l]);
return;
}
int mid=l+r>>1;
Binary(mid+1,r);
Cal(l,mid+1,r);
Binary(l,mid);
}
int main(){
n=Getint(),m=Getint(),T=Getint(),X=Getint();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i^j)mp[i][j]=MAXN;
for(int i=1;i<=m;i++){
int x=Getint(),y=Getint(),z=Getint();
s[i]=(node){x,y,z};
mp[x][y]=min(mp[x][y],1.0*z);
for(int j=1;j<=T;j++)p[i][j]=(double)Getint()/100000;
}
Floyd();
for(int j=T+1;j<=2*T;j++)f[n][j]=X;
for(int i=1;i<n;i++){
for(int j=0;j<=T;j++)f[i][j]=MAXN;
for(int j=T+1;j<=2*T;j++)f[i][j]=X+mp[i][n];
}
Cal(1,T+1,2*T);
Binary(0,T);
printf("%.6f",f[1][0]);
return 0;
}

最新文章

  1. Struts2使用demo
  2. 【USACO 2.3】Zero Sum(dfs)
  3. android获取textview的行数
  4. java基于socket公共聊天室的实现
  5. Android控件之ImageView(显示图片的控件)
  6. IntelliJ IDEA 比较当前版本文件与历史文件
  7. Javascript中的Cookie操作
  8. SQL点滴3—一个简单的字符串分割函数
  9. localStorage , sessionStorage ,cookie 使用介绍
  10. JAVA多线程之CountDownLatch
  11. 【English】十四、英语
  12. 在Pythonfor循环中如何获取循环次数?
  13. session and cookie
  14. Jenkins初级使用过程中的异常处理(1)
  15. Redis学习一(基础入门).
  16. React Native 调用 Web3(1.x) 的正确姿势
  17. python抢火车票 短信通知
  18. VS 函数,方法上方 引用等显示
  19. 手机H5移动端WEB资源整合之meta标签
  20. 线程同步-使用CountDownEvent类

热门文章

  1. 7年Java后端被淘汰,一路北漂辛酸史。。。
  2. sanic之websocket路由
  3. JavaScript小实例-文本循环变色效果
  4. spark自定义分区器实现
  5. FTT &amp; NTT &amp; 分治FFT
  6. Python自学:第五章 动手试一试 4-3
  7. centos做免密登录
  8. sublime快捷键汇总
  9. FreeMarker简单入门到使用
  10. Go 动态类型声明