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

    CF553E Kyoya and Train

    还是那句话,我觉得分治FFT是有实现难度的 初学,dalao别D

    看完题第一反应应该是设 (dp(i,j)) 表示时刻 (j) 到达点 (i) 的最小代价。

    发现完全不会处理边界,想了一会就舍掉了。

    (dp(i,j)) 表示时刻 (j)(i) 到达 (n) 的最小代价,那么答案就是 (dp(1,0))

    这个是可以转移的。

    [f(u,j)= egin{cases} (u=n) egin{cases} 0(jle t)\ x(jgt t)\ end{cases} \ (else) egin{cases} min{sum_{k=1}^{t} P_{(u,v),k}f(v,j+k)+w(u,v) } (jle t)\ dis(u,n)+x(jgt t)\ end{cases} end{cases} ]

    暴力是 (O(mt^2)) 的,倒序枚举 (t) 即可。

    然后就不会了。。。

    嗯,好,这个式子居然可以直接算出来,我只能爬,多项式nb。

    首先应当注意到 (sum_{k=1}^{t} P_{(u,v),k}f(v,j+k)) 是可以卷的,随便把一个多项式翻转就能卷了。

    问题在于我们必须知道所有 (j>i)(f(v,j)) 才能计算 (f(u,i)) ,如果暴力倒序枚举 (j) 复杂度又回去了。

    考虑分治FFT,这东西可以自己更新自己。应该先分治右区间再分治左区间。

    然而还是不会

    为啥不会算呢?仔细一想主要是复杂度不对,因为取 (min) ,每次必须把长度为 (t) 的多项式卷起来。

    然后我怎么就没想到搞一个可以直接加的东西出来哦/kk

    (g(i,j)) 表示 在 (j) 时刻开始走第 (i) 条边走到 (n) 的最短时间,那么 (f(a_i,j)=g(i,j))

    这个 (g(i,[l,mid])) 可以通过 (f(b_i,[mid+1,r])) 搞出来, 而且因为后半段的 (f) 已经确定,必然最优,直接相加没有错!

    递归到 (l=r) 的时候用 (g)(f) 更新掉就好了

    转移大概长这样:

    (钦定 (P_{i,0}=0)看着舒服)

    [g(i,x)=sum_{j=0}^{t}P_{i,j}f(b_i,x+j) ]

    用cdq分治的思路,不断统计右区间对左区间的贡献就能算出 (g) 了。

    然后就是非常烦的边界处理,一定想清楚再打,尽量不要调。但是我边界对了FFT打挂了是我没想到的

    (A_j=P_{i,j}(lle jle r),B_{r-j+mid+1}=f(b_i,r-j)(mid+1le r-jle r))

    (A,B) 卷起来看看是啥

    ([z^k]A*B=sum_{j=0}^{k}A_jB_{k-j}=sum _{j=0}^{k}P_{i,j}f(b_i,r-k+j))

    所以提取 (r-j) 这一项加到 (jin [l,mid]) 上即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    #define mkp(x,y) make_pair(x,y)
    #define pb(x) push_back(x)
    #define sz(v) (int)v.size()
    typedef long long LL;
    typedef double db;
    template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;}
    template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;}
    #define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
    #define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
    	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    	return f?x:-x;
    }
    const int V=55;
    const int E=105;
    const int N=20005;
    const int M=N<<2;
    const db inf=1e15;
    int n,m,t,X,a[E],b[E],c[E];
    db p[E][N<<1],dis[V][V],f[E][N<<1];
    
    namespace poly{
    
    const db PI=acos(-1.0);
    
    int rev[M],lg,lim;
    db g[E][N<<1];
    void init(const int&n){
    	for(lg=0,lim=1;lim<=n;++lg,lim<<=1);
    	for(int i=0;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
    }
    struct cp{
    	db x,y;
    	cp(){x=y=0;}
    	cp(db x_,db y_){x=x_,y=y_;}
    	cp operator + (const cp&t)const{return cp(x+t.x,y+t.y);}
    	cp operator - (const cp&t)const{return cp(x-t.x,y-t.y);}
    	cp operator * (const cp&t)const{return cp(x*t.x-y*t.y,x*t.y+y*t.x);}
    };
    void FFT(cp*a,int op){
    	for(int i=0;i<lim;++i)
    		if(i>rev[i])swap(a[i],a[rev[i]]);
    	for(int i=1;i<lim;i<<=1){
    		cp wn=cp(cos(PI/i),sin(PI/i)*(op?1:-1));
    		for(int j=0;j<lim;j+=i<<1){
    			cp w0=cp(1,0);
    			for(int k=0;k<i;++k,w0=w0*wn){
    				const cp X=a[j+k],Y=w0*a[i+j+k];
    				a[j+k]=X+Y,a[i+j+k]=X-Y;
    			}
    		}
    	}
    	if(op)return;
    	for(int i=0;i<lim;++i)a[i].x/=lim;
    }
    void CDQ_FFT(int l,int r){
    	if(l==t&&r==2*t-1)return;
    	static cp A[M],B[M];
    	if(l==r){
    		rep(i,1,n-1)f[i][l]=inf;
    		for(int i=1;i<=m;++i)if(a[i]!=n)ckmin(f[a[i]][l],g[i][l]+c[i]);
    		return;
    	}
    	int mid=(l+r)>>1;
    	CDQ_FFT(mid+1,r);
    	init(r-l+r-mid);
    	for(int i=1;i<=m;++i){
    		if(a[i]==n)continue;
    		for(int j=0;j<lim;++j)A[j]=B[j]=cp(0,0);
    		for(int j=0;j<=r-l;++j)A[j].x=p[i][j];
    		for(int j=mid+1;j<=r;++j)B[j-mid-1].x=f[b[i]][r-j+mid+1];
    		FFT(A,1),FFT(B,1);
    		for(int j=0;j<lim;++j)A[j]=A[j]*B[j];
    		FFT(A,0);
    		for(int j=l;j<=mid;++j)g[i][j]+=A[r-j].x;
    	}
    	CDQ_FFT(l,mid);
    }
    }
    signed main(){
    	n=read(),m=read(),t=read(),X=read();
    	rep(i,1,n)rep(j,1,n)dis[i][j]=i==j?0:inf;
    	for(int i=1;i<=m;++i){
    		a[i]=read(),b[i]=read(),c[i]=dis[a[i]][b[i]]=read();
    		rep(j,1,t)p[i][j]=1.*read()/100000;
    	}
    	rep(k,1,n)rep(i,1,n)rep(j,1,n)ckmin(dis[i][j],dis[i][k]+dis[k][j]);
    	rep(i,1,n-1)rep(j,t,t*2-1)f[i][j]=dis[i][n]+X;
    	rep(i,0,t*2-1)f[n][i]=i<=t?0:X;
    	poly::CDQ_FFT(0,t*2-1);
    	printf("%.9lf
    ",f[1][0]);
    	return 0;
    }
    
    
  • 相关阅读:
    mac下给git://协议设置代理Proxy
    安卓手机中wifi密码查看器,查看wifi密码教程
    坑爹啊!gradle 2.1构建android出现错误的解决方案
    php-fpm开启报错-ERROR: An another FPM instance seems to already listen on /tmp/php-cgi.sock详解
    git rebase 还是 merge的使用场景最通俗的解释
    git rebase 与 git merge 的区别
    zend opcache的最佳设置(仅做参考)
    PHP7.3 报错: A non well formed numeric value encountered
    关于PHP.ini的opcache中opcache.revalidate_freq参数设置测试报告
    微信小程序登录实现,前端+后端PHP代码(前端获得CODE,后端获取微信用户的OPEN ID 和 UNION ID)
  • 原文地址:https://www.cnblogs.com/zzctommy/p/14209728.html
Copyright © 2011-2022 走看看