zoukankan      html  css  js  c++  java
  • CF553E Kyoya and Train

    一、题目

    点此看题

    二、解法

    (dp[i][j]) 表示 (j) 时间走到 (i) 需要花费的最小期望钱数。

    区别于随机游走问题,对于某状态 (dp[u][j]),需要决策一个后继节点 (v)

    [dp[u][j]=min_v(sum_k dp[v][j+k] imes p_{u,k})+c_i ]

    末状态 (dp[u][i]=dis(u,n)+x,i>t)(dp[n][i]=0,ileq t)

    时间复杂度 (O(mt^2))


    考虑优化,看到 (min) 里面的求和你可能会想到 ( t FFT),但是不能直接一发差卷积搞上去,因为本题转移顺序最外层是时间,如果你差卷积是默认知道 (dp[v]) 的所有状态的。所以我们要对时间分治,写一个分治 ( t FFT)

    我们把右边的 (f[v[i]]) 转移到一个 (g[i]) 中,分治到底层的时候再用 (g[i]) 去更新 (f[u[i]]),然后这道题给 ( t FFT) 配系数时把我整傻了,还是要推柿子更有助于理解:

    [g_x=sum_{i=mid+1}^rp_{i-x}f_i ]

    (a_i=p_{i+1},b_i=f_{r-i}),那么把求和柿子改写一下:

    [g_x=sum_{i=0}^{r-mid-1} a_{i-x+mid}b_{r-i-mid-1} ]

    设卷出来的数组是 (c),那么让 (g_x=c_{r-x-1}) 即可,时间复杂度 (O(tlog tcdot m))

    三、总结

    优化转移的时候不仅要看结构,还要看顺序,特别是图问题中,保证转移顺序是优化的前提。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    using namespace std;
    const int M = 105;
    const int N = 80005;
    #define db double
    const db pi = acos(-1.0);
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,t,x,u[M],v[M],c[M],d[M][M],rev[N];
    db f[M][N],g[M][N],p[M][N];
    struct comp
    {
    	db x,y;
    	comp(db X=0,db Y=0) : x(X) , y(Y) {}
    	comp operator + (const comp &r) const {return comp(x+r.x,y+r.y);}
    	comp operator - (const comp &r) const {return comp(x-r.x,y-r.y);}
    	comp operator * (const comp &r) const {return comp(x*r.x-y*r.y,x*r.y+y*r.x);}
    }A[N],B[N],C[N];
    void FFT(comp *a,int len,int op)
    {
    	for(int i=0;i<len;i++)
    	{
    		rev[i]=(rev[i>>1]>>1)|((i&1)*(len/2));
    		if(i<rev[i]) swap(a[i],a[rev[i]]);
    	}
    	for(int s=2;s<=len;s<<=1)
    	{
    		comp w=comp(cos(2*pi/s),sin(2*pi/s)*op);
    		for(int i=0,t=s/2;i<len;i+=s)
    		{
    			comp x=comp(1,0);
    			for(int j=0;j<t;j++,x=x*w)
    			{
    				comp fe=a[i+j],fo=a[i+j+t];
    				a[i+j]=fe+x*fo;
    				a[i+j+t]=fe-x*fo;
    			}
    		}
    	}
    }
    void cdq(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++)
    			f[u[i]][l]=min(f[u[i]][l],g[i][l]);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	cdq(mid+1,r);
    	for(int i=1;i<=m;i++)
    	{
    		int ln=r-l,lm=r-mid,len=1;
    		while(len<ln+lm) len<<=1;
    		for(int j=0;j<len;j++) A[j]=B[j]=C[j]=comp(0,0);
    		for(int j=0;j<ln;j++) A[j]=comp(p[i][j+1],0);
    		for(int j=0;j<lm;j++) B[j]=comp(f[v[i]][r-j],0);
    		FFT(A,len,1);FFT(B,len,1);
    		for(int j=0;j<len;j++) C[j]=A[j]*B[j];
    		FFT(C,len,-1);
    		for(int j=l;j<=mid;j++)
    			g[i][j]+=C[r-j-1].x/len;
    	}
    	cdq(l,mid);
    }
    signed main()
    {
    	n=read();m=read();t=read();x=read();
    	memset(d,0x3f,sizeof d);
    	for(int i=1;i<=m;i++)
    	{
    		u[i]=read();v[i]=read();c[i]=read();
    		d[u[i]][v[i]]=c[i];
    		for(int j=1;j<=t;j++) p[i][j]=read()/1e5;
    	}
    	for(int i=1;i<=n;i++) d[i][i]=0;//attention
    	for(int k=1;k<=n;k++)
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=n;j++)
    				d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
    	for(int i=1;i<=m;i++)
    	{
    		db s=0;
    		for(int j=0;j<=t;s+=p[i][t-j],j++)
    			g[i][j]=s*(d[v[i]][n]+x)+c[i];
    	}
    	cdq(0,t);
    	printf("%.7f
    ",min(f[1][0],0.0+x+d[1][n]));
    }
    
  • 相关阅读:
    Redux
    React-Router常见API
    webpack的plugin原理
    Kubernetes核心原理笔记
    阿里云证书过期时间监测
    DRF
    一个TCP可以发送多少个请求
    jenkins exporter(收集jenkins构建结果)
    Kubernetes SDN
    Django REST framework API认证(包括JWT认证)
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15037366.html
Copyright © 2011-2022 走看看