• 【CF553E】Kyoya and Train(期望dp,SPFA,FFT)


    考虑 dp。

    发现正着 dp 好像不太好做,毕竟初值不太好设,而且时间一大于 t t t 费用就要加上 x x x,所以考虑倒着 dp。

    f u , j f_{u,j} fu,j 表示现在已经到达 u u u 点,耗时 j j j,问到达 n n n 点的最小期望费用。

    容易得到边界条件: f i , j = d i s i + x ( j > t ) f_{i,j}=dis_i+x(j>t) fi,j=disi+x(j>t)(其中 d i s i dis_i disi 表示 i i i n n n 的最短路,可以用dijkstra 预处理),这个很好解释,一旦时间大于 t t t 了,那么肯定要罚款,所以我们不用再关注时间这一状态了。

    同时也容易得到状态转移方程:
    f u , j = min ⁡ ( u , v ) ( w ( u , v ) + ∑ k = 1 t p ( u , v ) , k × f v , j + k ) f_{u,j}=min _{(u,v)}left(w_{(u,v)}+sum_{k=1}^{t}p_{(u,v),k} imes f_{v,j+k} ight) fu,j=(u,v)min(w(u,v)+k=1tp(u,v),k×fv,j+k)
    用 SPFA 转移的话,时间复杂度是 O ( n m t 2 ) O(nmt^2) O(nmt2),不能接受

    i = ( u , v ) i=(u,v) i=(u,v),设 g i , j = ∑ k = 1 t p i , k × f v , j + k g_{i,j}=sumlimits_{k=1}^{t}p_{i,k} imes f_{v,j+k} gi,j=k=1tpi,k×fv,j+k

    发现 p p p f f f 的第二维相减是个和 k k k 无关的值 j j j,所以考虑把它化成卷积形式。

    p ^ i = p t − k + 1 hat{p}_i=p_{t-k+1} p^i=ptk+1,那么 g i , j = ∑ k = 1 t p ^ i , t − k + 1 × f v , j + k g_{i,j}=sumlimits_{k=1}^{t}hat{p}_{i,t-k+1} imes f_{v,j+k} gi,j=k=1tp^i,tk+1×fv,j+k p p p f f f 的第二维相加是定值 t + j + 1 t+j+1 t+j+1,是个卷积的形式。

    不妨设 A = p ^ i A=hat{p}_i A=p^i B = f v B=f_v B=fv C = g i C=g_i C=gi,那么 C = A B C=AB C=AB

    所以我们不必枚举 j j j k k k,而是对于每一个 i i i,一遍 FFT 就能求出所有的 g i , j g_{i,j} gi,j

    那么时间复杂度就成功降到了 O ( n m t log ⁡ t ) O(nmtlog t) O(nmtlogt)

    至于更优秀的分治 FFT 做法蒟蒻表示并不会。

    代码如下:

    #include<bits/stdc++.h>
    
    #define N 55
    #define M 110
    #define T 20010
    #define INF 0x7fffffff
    
    using namespace std;
    
    const double pi=acos(-1);
    
    struct Complex
    {
    	double x,y;
    	Complex(){x=y=0;};
    	Complex(double a,double b){x=a,y=b;}
    }A[T<<3],B[T<<3],C[T<<3];
    
    Complex operator + (Complex a,Complex b){return Complex(a.x+b.x,a.y+b.y);}
    Complex operator - (Complex a,Complex b){return Complex(a.x-b.x,a.y-b.y);}
    Complex operator * (Complex a,Complex b){return Complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
    
    struct data
    {
    	int u,s;
    	data(){};
    	data(int a,int b){u=a,s=b;}
    	bool operator < (const data &a) const
    	{
    		return s>a.s;
    	}
    };
    
    int n,m,t,x;
    int cnt,head[N],nxt[M],to[M],w[M];
    int dis[N];
    bool vis[N],inq[N];
    double p[M][T<<3],f[N][T<<3],now[T<<3];
    int bit=0,limit=1;
    int rev[T<<3];
    
    void FFT(Complex *a,int opt)
    {
    	for(int i=0;i<limit;i++)
    		if(i<rev[i]) swap(a[i],a[rev[i]]);
    	for(int mid=1;mid<limit;mid<<=1)
    	{
    		int len=mid<<1;
    		Complex wn=Complex(cos(pi/mid),opt*sin(pi/mid));
    		for(int i=0;i<limit;i+=len)
    		{
    			Complex omega=Complex(1,0);
    			for(int j=0;j<mid;j++,omega=omega*wn)
    			{
    				Complex x=a[i+j],y=omega*a[i+mid+j];
    				a[i+j]=x+y,a[i+mid+j]=x-y;
    			}
    		}
    	}
    	if(opt==-1)
    		for(int i=0;i<limit;i++)
    			a[i].x/=limit;
    }
    
    void mul(double *a,double *b,double *c)
    {
    	for(int i=0;i<=t*2;i++) A[i]=Complex(a[i],0);
    	for(int i=0;i<=t*2;i++) B[i]=Complex(b[i],0);
    	for(int i=t*2+1;i<limit;i++) A[i]=B[i]=Complex(0,0);
    	FFT(A,1),FFT(B,1);
    	for(int i=0;i<limit;i++) C[i]=A[i]*B[i];
    	FFT(C,-1);
    	for(int i=0;i<limit;i++) c[i]=C[i].x;
    }
    
    void adde(int u,int v,int wi)
    {
    	to[++cnt]=v;
    	w[cnt]=wi;
    	nxt[cnt]=head[u];
    	head[u]=cnt;
    }
    
    void dijkstra()
    {
    	priority_queue<data>q;
    	memset(dis,127,sizeof(dis));
    	dis[n]=0;
    	q.push(data(n,dis[n]));
    	while(!q.empty())
    	{
    		data now=q.top();
    		q.pop();
    		if(vis[now.u]) continue;
    		vis[now.u]=1;
    		for(int i=head[now.u];i;i=nxt[i])
    		{
    			int v=to[i];
    			if(dis[now.u]+w[i]<dis[v])
    			{
    				dis[v]=dis[now.u]+w[i];
    				q.push(data(v,dis[v]));
    			}
    		}
    	}
    }
    
    void SPFA()
    {
    	queue<int>q;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=0;j<=t;j++) f[i][j]=INF;
    		for(int j=t+1;j<=2*t;j++) f[i][j]=dis[i]+x;
    	}
    	for(int j=0;j<=t;j++) f[n][j]=0;
    	q.push(n);
    	inq[n]=1;
    	while(!q.empty())
    	{
    		int u=q.front();
    		q.pop();
    		inq[u]=0;
    		for(int i=head[u];i;i=nxt[i])
    		{
    			int v=to[i];
    			mul(f[u],p[i],now);
    			bool flag=false;
    			for(int j=0;j<=t;j++)
    			{
    				if(now[t+j+1]+w[i]<f[v][j])
    				{
    					f[v][j]=now[t+j+1]+w[i];
    					flag=1;
    				}
    			}
    			if(flag)
    			{
    				if(!inq[v])
    				{
    					inq[v]=1;
    					q.push(v);
    				}
    			}
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d%d%d",&n,&m,&t,&x);
    	for(int i=1;i<=m;i++)
    	{
    		int u,v,w;
    		scanf("%d%d%d",&u,&v,&w);
    		adde(v,u,w);
    		for(int j=t;j>=1;j--)
    		{
    			scanf("%lf",&p[i][j]);
    			p[i][j]/=1e5;
    		}
    	}
    	while(limit<=(t<<2)) limit<<=1,bit++;
    	for(int i=0;i<limit;i++)
    		rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
    	dijkstra();
    	SPFA();
    	printf("%.10lf
    ",f[1][0]);
    	return 0;
    }
    
  • 相关阅读:
    开发一个基于 Android系统车载智能APP
    Xilium.CefGlue利用XHR实现Js调用c#方法
    WPF杂难解 奇怪的DisconnectedItem
    (转)获取安卓iOS上的微信聊天记录、通过Metasploit控制安卓
    mac 安装npm
    mac安装Homebrew
    关于面试,我也有说的
    【分享】小工具大智慧之Sql执行工具
    领域模型中分散的事务如何集中统一处理(C#解决方案)
    小程序大智慧,sqlserver 注释提取工具
  • 原文地址:https://www.cnblogs.com/ez-lcw/p/14448625.html
Copyright © 2020-2023  润新知