zoukankan      html  css  js  c++  java
  • Codeforces 553E Kyoya and Train

    题目大意

    链接: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)=minlimits_{ein E}{val_{e}+sum_{i=1}^Tp_{e,i}cdot f(y,t+i)} ]

    时间复杂度(O(ncdot T^2))

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

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


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

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

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

    我们可以利用分治。

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

    先求出(mid<tleq r)(f),并用这些(f)去更新(lleq tleq mid)(g),然后递归下去即可。


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

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

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

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

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

    即:(g(e,mid-x)+=sumlimits_{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;
    }
    
  • 相关阅读:
    阶段3 3.SpringMVC·_03.SpringMVC常用注解_1 RequestParam注解
    阶段3 3.SpringMVC·_02.参数绑定及自定义类型转换_7 获取Servlet原生的API
    函数传参
    利用 操作符特性 代替if判断语句
    for(;;)和 while(1) 有什么区别吗?for()和while()的使用情景。
    一个简单的mfc单页界面文件读写程序(MFC 程序入口和执行流程)
    ARM异常---一个DataAbort的触发过程:
    C语言,单链表操作(增删改查)(version 0.1)
    Cpu实验
    H-JATG:NAND_FLASH的参数设置
  • 原文地址:https://www.cnblogs.com/Emiya-wjk/p/10040948.html
Copyright © 2011-2022 走看看