码迷,mamicode.com
首页 > 其他好文 > 详细

CF553E Kyoya and Train

时间:2021-01-04 10:32:05      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:ati   code   ack   复杂度   处理   printf   long   def   分治   

CF553E Kyoya and Train

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

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

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

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

这个是可以转移的。

\[f(u,j)= \begin{cases} (u=n) \begin{cases} 0(j\le t)\x(j\gt t)\\end{cases} \(else) \begin{cases} \min\{\sum_{k=1}^{t} P_{(u,v),k}f(v,j+k)+w(u,v) \} (j\le t)\dis(u,n)+x(j\gt 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\)\(l\) 更新掉就好了

转移大概长这样:

(钦定 \(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}(l\le j\le r),B_{r-j+mid+1}=f(b_i,r-j)(mid+1\le r-j\le 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\) 这一项加到 \(j\in [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\n",f[1][0]);
	return 0;
}

CF553E Kyoya and Train

标签:ati   code   ack   复杂度   处理   printf   long   def   分治   

原文地址:https://www.cnblogs.com/zzctommy/p/14209728.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!