http://codeforces.com/problemset/problem/553/E (题目链接)

艹尼玛,CF还卡劳资常数w(゚Д゚)w!!系统complex被卡TLE了T_T,劳资写了一天一夜啊!!博客都写了这么长啊!!

题意

  ${n}$个点${m}$条边的有向图,给出起点和终点,如果不能在${T}$时间内到达终点则需要付出一定的代价,走每条边需要付出给定的代价,每条边经过时间的分布列给定,最小化所需要的期望的代价。

Solution

  毛爷爷论文题。

  先考虑暴力${DP}$怎么做。${f_{x,t}}$表示到达${x}$点,花费时间${t}$所期望的最小代价。那么转移很显然,对于从${x}$出发的每一条边${e_i=(x,y_i)}$,设${P_{e_i,t}}$为走这条边经过时间${t}$的概率,那么转移方程:$${f_{x,t}=Min \{\sum_{j=1}^{T} {f_{y_i,t+j}*P_{e_i,j}}\}}$$

  刚开始一直不太理解这个${DP}$,题目中并没有保证给出的有向图是个${DAG}$,那这样的${DP}$不应该用高斯消元求解吗。其实可以这样理解,我们把图看做是按照时间分层的有向图,每一条边至少要花费${1}$的时间,那么一个点就不可能再回到它的祖先,除非它经过的边的时间为负数。那么整个图就构成了一个${DAG}$,就可以${DP}$了。于是状态${O(T*m)}$,转移${O(T)}$,复杂度${O(m*T*T)}$,GG,考虑怎么对这个${DP}$进行优化。对于每一条边${e}$,我们用${S_{e,t}}$表示上面这个转移方程的右边${S_{e,t}=\sum_{j=1}^{T} {f_{y_i,t+j}*P_{e_i,j}}}$。那么很显然,${f}$的转移方程就可以改为:$${f_{x.t}=Min \{S_{e_i,t}\}}$$

  这样做有什么用呢,我们对时间分治(当然,此时间非彼时间)。如果我们要求出所有${l<=t<=r}$的对应到所有边的${f_{x,t}}$和${S{e,t}}$,那么我们设${mid=\lceil\frac{l+r}{2}\rceil}$,先求出所有${mid<=t<=r}$的${f_{x,t}}$,然后再用这些${f_{x,t}}$去更新${l<=t<mid}$的${S_{e,t}}$,接下来递归求解${l<=r<mid}$的${f_{x,t}}$。如果${l=r}$那么直接用${S}$去更新${f}$。怎么用${f}$去更新${S}$呢,我们运用${FFT}$。$${S_{e,t}=\sum_{j=1}^{T} {f_{y_i,t+j}*P_{e_i,j}}}$$

  这个东西长的就像个卷积,我们考虑怎么将它化为卷积的模式。假设现在我们计算${mid<=t<=r}$,边${e}$中,${f_{x,t}}$对${S_{e,mid-2}}$的贡献,那么如图所示:

  这样的一个相乘的过程怎么转化为卷积呢,我们将${f_x}$倒过来,并在它的末尾添${0}$,就得到了卷积的形式:

  于是我们就可以构造多项式:$${A(t)=\sum_{i=0}^{r-mid+1}  {f_{x,r-i}×t^i}   +   \sum_{i=r-mid+2}{T-1}  {0×t^i}}$$

$${B(t)=\sum_{i=0}^{T-1}  {P_{e,i+1}×t^i}}$$

$${C=A×B}$$

  那么我们可以发现,${l<=t<mid}$中,${S_{e,t}}$得到的贡献就是卷积${c_{r-t-1}=\sum_{j=0}^{r-t-1}  {a_j×b_{r-t-1-j}}}$

细节

  感觉这道题细节还是蛮多的,脑袋晕晕的写了一天,都怪昨天睡太晚→_→。不如讨论一下一些需要注意的细节。

  第一,数组怎么开。${DP}$相关的数组的时间一维可能会很大,我们考虑当时间超过${T}$之后,具体的到达终点的时间已经对我们没有意义了,反正要罚钱,不如走一条买的票最便宜的路线到达终点。所以对于${f_{x,t}=dis(x,n)+X;t>T}$。考虑时间这一维要开大的数组,我们从一种状态${f_{x,t},t<=T}$,它最多可能转移到的状态的${t}$不会超过${2*T}$,因为一条路线最多耗费时间${T}$;而对于第二种状态${f_{x,t},t>T}$,我们可以很轻松的求出它,已经没有转移的必要了。于是乎,时间这一维的数组大小需要开到${2*T}$。

  第二,考虑分治的初始化。首先,对于${T<t<=2*T}$的${f}$,它已经不需要再求一遍了,所以我们直接分治${solve(0,T)}$。在分治求解之前,我们需要计算${T<t<=2*T}$的${f}$对之前的${S}$的贡献,所以先做一遍${FFT}$,再进行分治求解。

  第三,就是${FFT}$时下标之间的对应关系。

代码

// codeforces 553E
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<complex>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#define LL long long
#define inf 1ll<<30
#define Pi acos(-1.0)
#define upd(x,y) if ((x)>(y)) (x)=(y)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
inline int gi() {
int x=0,f=1;char ch=getchar();
while (ch<'0' || ch>'9') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
} //typedef complex<double> E;
const int maxn=110,maxm=210,maxt=20010;
//E A[maxt<<2],B[maxt<<2];
int rev[maxt<<2],dis[maxn][maxn],n,m,T,X,N,L;
double f[maxn][maxt<<1],P[maxm][maxt<<1],S[maxm][maxt<<1]; struct edge {int u,v,w;}e[maxm];
struct E{ double x,y; }A[maxt<<2],B[maxt<<2];
inline E operator + (const E &a,const E &b) { return (E){a.x+b.x,a.y+b.y}; }
inline E operator - (const E &a,const E &b) { return (E){a.x-b.x,a.y-b.y}; }
inline E operator * (const E &a,const E &b) { return (E){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x}; } void FFT(E *a,int f) {
for (int i=0;i<N;i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
for (int i=1;i<N;i<<=1) {
E wn=(E){cos(Pi/i),f*sin(Pi/i)};
for (int p=i<<1,j=0;j<N;j+=p) {
E w=(E){1,0};
for (int k=0;k<i;k++,w=w*wn) {
E x=a[j+k],y=a[j+k+i]*w;
a[j+k]=x+y;a[j+k+i]=x-y;
}
}
}
}
void calculate(int l,int r,int mid) {
int len=r-l;
for (int j=1;j<=m;j++) {
L=-1;for (N=1;N<=len-1+r-mid;N<<=1) L++; //mdzz错误又犯了
for (int i=0;i<N;i++) rev[i]=(rev[i>>1]>>1) | ((i&1)<<L);
for (int i=0;i<N;i++) A[i]=B[i]=(E){0,0};
for (int i=0;i<r-mid+1;i++) A[i]=(E){f[e[j].v][r-i],0};
for (int i=0;i<len;i++) B[i]=(E){P[j][i+1],0};
FFT(A,1);FFT(B,1);
for (int i=0;i<N;i++) A[i]=A[i]*B[i];
FFT(A,-1);
for (int i=mid-1;i>=l;i--) S[j][i]+=A[r-i-1].x/N;
}
}
void solve(int l,int r) {
if (l==r) {
for (int i=1;i<=m;i++) f[e[i].u][l]=min(f[e[i].u][l],S[i][l]+e[i].w);
return;
}
int mid=(l+r)>>1;
solve(mid+1,r);
calculate(l,r,mid+1);
solve(l,mid);
} int main() {
n=gi(),m=gi(),T=gi(),X=gi();
for (int i=1;i<=n;i++) {
for (int j=1;j<=n;j++) dis[i][j]=inf;
dis[i][i]=0;
}
for (int i=1;i<=m;i++) {
e[i].u=gi(),e[i].v=gi(),e[i].w=gi();
dis[e[i].u][e[i].v]=min(dis[e[i].u][e[i].v],e[i].w);
for (int x,j=1;j<=T;j++) {
x=gi();
P[i][j]=(double)x/100000;
}
}
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j && j!=k && i!=k && dis[i][k]!=inf && dis[k][j]!=inf)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
for (int i=0;i<=T;i++) f[n][i]=0;
for (int i=T+1;i<=2*T;i++) f[n][i]=X;
for (int i=1;i<n;i++)
for (int j=0;j<=2*T;j++) {
if (j>T) f[i][j]=dis[i][n]+X;
else f[i][j]=inf;
}
calculate(1,T*2,T+1);
solve(0,T);
printf("%.6lf\n",f[1][0]);
return 0;
}

【codeforces 553E】 Kyoya and Train的更多相关文章

  1. 【47.95%】【codeforces 554C】Kyoya and Colored Balls

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  2. 【76.83%】【codeforces 554A】Kyoya and Photobooks

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  3. 【CF553E】Kyoya and Train 最短路+cdq分治+FFT

    [CF553E]Kyoya and Train 题意:有一张$n$个点到$m$条边的有向图,经过第i条边要花$c_i$元钱,经过第i条边有$p_{i,k}$的概率要耗时k分钟.你想从1走到n,但是如果 ...

  4. 【codeforces 415D】Mashmokh and ACM(普通dp)

    [codeforces 415D]Mashmokh and ACM 题意:美丽数列定义:对于数列中的每一个i都满足:arr[i+1]%arr[i]==0 输入n,k(1<=n,k<=200 ...

  5. 【50.00%】【codeforces 602C】The Two Routes

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  6. 【33.33%】【codeforces 586D】Phillip and Trains

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  7. 【codeforces 707E】Garlands

    [题目链接]:http://codeforces.com/contest/707/problem/E [题意] 给你一个n*m的方阵; 里面有k个联通块; 这k个联通块,每个连通块里面都是灯; 给你q ...

  8. 【codeforces 707C】Pythagorean Triples

    [题目链接]:http://codeforces.com/contest/707/problem/C [题意] 给你一个数字n; 问你这个数字是不是某个三角形的一条边; 如果是让你输出另外两条边的大小 ...

  9. 【codeforces 709D】Recover the String

    [题目链接]:http://codeforces.com/problemset/problem/709/D [题意] 给你一个序列; 给出01子列和10子列和00子列以及11子列的个数; 然后让你输出 ...

随机推荐

  1. 1.VBA 基本概念——《Excel VBA 程序开发自学宝典》

    1.1 常见对象及含义 对象名 含义 application 整个Excel应用程序 window 窗口 worksheet  一个工作表 sheets 指定工作簿的所有工作表的合集 shaperan ...

  2. 32bit 天堂2服务端多机负载

    第一步..先确定..单机架设成功.. 第二步..复制整个服务器端文件到第2个服务器 第3步.. 将你C:\Program Files\Common Files\ODBC\Data Sources 中的 ...

  3. 我用Python远程探查室友的网页浏览记录,他不愧是成年人!

    过程: 利用Python制作远程查看别人电脑的操作记录,与其它教程类似,都是通过邮件返回. 利用程序得到目标电脑浏览器当中的访问记录,生产一个文本并发送到你自己的邮箱,当然这个整个过程除了你把pyth ...

  4. 【Coursera-ML-Notes】线性回归(上)

    什么是机器学习 关于机器学习,有以下两种不同的定义. 机器学习是研究如何使电脑具备学习能力,而不用显式编程告诉它该怎么做. the field of study that gives computer ...

  5. 吴恩达 Deep learning 第二周 神经网络基础

    逻辑回归代价函数(损失函数)的几个求导特性 1.对于sigmoid函数 2.对于以下函数 3.线性回归与逻辑回归的神经网络图表示 利用Numpy向量化运算与for循环运算的显著差距 import nu ...

  6. Java之JSP和Servlet基础知识

    JSP基础 JSP起源 JSP,JavaServer Pager的简称.由SUN倡导并联合其它公司创建. JSP是一门脚本语言 JSP可以嵌入到HTML中 JSP拥有Java语言的所有特性 面向对象. ...

  7. (转)Django 数据库

         转:https://blog.csdn.net/ayhan_huang/article/details/77575186      目录 数据库说明 配置数据库 在屏幕输出orm操作对应的s ...

  8. C++ 类 复制构造函数 The Copy Constructor

    一.复制构造函数的定义 复制构造函数是一种特殊的构造函数,具有一般构造函数的所有特性.复制构造函数创建一个新的对象,作为另一个对象的拷贝.复制构造函数只含有一个形参,而且其形参为本类对象的引用.复制构 ...

  9. “Hello World!团队”Final发布—视频链接+文案+美工

    视频发布:http://www.bilibili.com/video/av17022373/ 文案加美工:http://www.cnblogs.com/chjy/p/7990116.html SkyH ...

  10. struts2 Action生命周期

    Struts2.0中的对象既然都是线程安全的,都不是单例模式,那么它究竟何时创建,何时销毁呢? 这个和struts2.0中的配置有关,我们来看struts.properties ### if spec ...