zoukankan      html  css  js  c++  java
  • 【CF553E】Kyoya and Train 最短路+cdq分治+FFT

    【CF553E】Kyoya and Train

    题意:有一张$n$个点到$m$条边的有向图,经过第i条边要花$c_i$元钱,经过第i条边有$p_{i,k}$的概率要耗时k分钟。你想从1走到n,但是如果整个过程耗时超过了$t$,则需要额外花费$f$元。求从1走到n的期望最小花费。

    $nle 50,mle 100,tle 20000,kle 1$

    题解:我们先用最短路预处理出如果已经超时了,从1走到n的最小花费。剩下的考虑DP。

    用f[i][j]表示在i时刻到达了j,想走到n的最小花费。则对于第i条边$(a,b)$,我们有:

    $f[a][j]=min(f[a][j],sum f[b][j+k]p_{i,k})$

    发现只有后面的时间会影响前面的时间,所以我们对时间进行cdq分治。再令g[i][j]表示在j时刻经过第i条边,想走到n的最小花费,那么对于边(a,b),我们可以用f[b]更新g[b],在用g[b]和f[a]取min即可。g[b]的转移如下:

    $g[i][j]=sum f[b][j+k]p_{i,k}$

    你会发现这是一个卷积的形式,上fft即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #define pi acos(-1.0)
    using namespace std;
    const int maxn=20010;
    typedef double db;
    struct cp
    {
    	db x,y;
    	cp() {}
    	cp(db a,db b) {x=a,y=b;}
    	cp operator + (const cp &a) const {return cp(x+a.x,y+a.y);}
    	cp operator - (const cp &a) const {return cp(x-a.x,y-a.y);}
    	cp operator * (const cp &a) const {return cp(x*a.x-y*a.y,x*a.y+y*a.x);}
    }l1[100010],l2[100010];
    int head[60],next[110],to[110],pa[110],pb[110],pc[110],vis[60],dis[60];
    db p[110][20010],F,f[60][20010],g[110][20010],sp[110][20010];
    int n,m,T;
    inline void FFT(cp *a,int len,int f)
    {
    	int i,j,k,h;
    	cp t;
    	for(i=k=0;i<len;i++)
    	{
    		if(i>k)	swap(a[i],a[k]);
    		for(j=len>>1;(k^=j)<j;j>>=1);
    	}
    	for(h=2;h<=len;h<<=1)
    	{
    		cp wn(cos(2*pi*f/h),sin(2*pi*f/h));
    		for(i=0;i<len;i+=h)
    		{
    			cp w(1,0);
    			for(j=i;j<i+h/2;j++)	t=w*a[j+h/2],a[j+h/2]=a[j]-t,a[j]=a[j]+t,w=w*wn;
    		}
    	}
    	if(f==-1)	for(i=0;i<len;i++)	a[i].x/=len;
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    void solve(int l,int r)
    {
    	if(l==r)
    	{
    		for(int i=1;i<n;i++)	f[i][l]=1e9;
    		for(int i=1;i<=m;i++)
    		{
    			g[i][l]+=sp[i][T-l+1]*(dis[pb[i]]+F);
    			f[pa[i]][l]=min(f[pa[i]][l],g[i][l]+pc[i]);
    		}
    		return ;
    	}
    	int mid=(l+r)>>1,i,j,len;
    	for(len=1;len<r-l+r-mid;len<<=1);
    	solve(mid+1,r);
    	for(j=1;j<=m;j++)
    	{
    		memset(l1,0,sizeof(l1[0])*len),memset(l2,0,sizeof(l2[0])*len);
    		for(i=1;i<=r-l;i++)	l1[r-l-i].x=p[j][i];
    		for(i=mid+1;i<=r;i++)	l2[i-mid-1].x=f[pb[j]][i];
    		FFT(l1,len,1),FFT(l2,len,1);
    		for(i=0;i<len;i++)	l1[i]=l1[i]*l2[i];
    		FFT(l1,len,-1);
    		for(i=0;i<mid-l+1;i++)	g[j][l+i]+=l1[r-mid-1+i].x;
    	}
    	solve(l,mid);
    }
    int main()
    {
    	//freopen("cf553E.in","r",stdin);
    	n=rd(),m=rd(),T=rd(),F=rd();
    	int i,j;
    	for(i=1;i<=m;i++)
    	{
    		pa[i]=rd(),pb[i]=rd(),pc[i]=rd();
    		for(j=1;j<=T;j++)	p[i][j]=rd()*0.00001;
    		for(j=T;j;j--)	sp[i][j]=sp[i][j+1]+p[i][j];
    	}
    	memset(dis,0x3f,sizeof(dis));
    	dis[n]=0;
    	for(i=1;i<=n;i++)
    	{
    		int k=0;
    		for(j=1;j<=n;j++)	if(!vis[j]&&dis[j]<dis[k])	k=j;
    		vis[k]=1;
    		for(j=1;j<=m;j++)	if(pb[j]==k)	dis[pa[j]]=min(dis[pa[j]],dis[k]+pc[j]);
    	}
    	solve(0,T);
    	printf("%.10lf",f[1][0]);
    	return 0;
    }
  • 相关阅读:
    合肥程序员欢迎进QQ群49313181同城程序员职业交流群
    新一代程序员的思考
    ThinkPHP开发系列一框架搭建
    ASP.NET MVC4+EF系列之五 架构介绍
    ASP.NET MVC4+EF系列之阶段源码一
    gcc g++ Linux下动态库_静态库 指定路径问题
    [转]accept() 产生的Socekt端口是多少?
    阿里云计算资深总监唐洪:飞天大规模分布式计算系统解析
    [转] C++中##(两个井号)和#(一个井号)用法
    deep learning 深度学习
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8685558.html
Copyright © 2011-2022 走看看