Codeforces 553E Kyoya and Train

题目大意

链接:CF533E

给一张\(n\)个点,\(m\)条边的图,起点\(1\)终点\(n\),如果不能在\(T\)的时间内到达则需支付\(X\)的代价。

走每条边都会支付一定代价,经过一条边\(i\)的时间有\(p_{i,j}\)的概率为\(j\),最小化期望代价。

题目分析

暴力方法:期望DP

设\(f_{i,j}\)表示在第\(j\)时刻,从\(i\)点出发,到达终点的期望花费,

设边为\(e\),边上两点为\(x,y\),边集为\(E\),则有
\[
f(x,t)=\min\limits_{e\in E}\{val_{e}+\sum_{i=1}^Tp_{e,i}\cdot f(y,t+i)\}
\]

时间复杂度\(O(n\cdot T^2)\)。

或许你会觉得这样转移有问题,因为这不是一个DAG图,

但是,由于没有负权环,一个点不可能回到它的祖先,所以我们可以当做DAG来处理。



现在想想怎么优化这个DP。

我们设\(g_{e,t}\)表示\(\sum\limits_{i=1}^Tp_{e,i}\cdot f(y,t+i)\),显然有
\[
f(x,t)=\min\{val_e+g(e,t)\}
\]

我们可以利用分治。

如果要求出\(l\leq t\leq r\)的所有\(f(x,t)\)和\(g(e,t)\),不妨设\(mid=l+r>>1\),

先求出\(mid<t\leq r\)的\(f\),并用这些\(f\)去更新\(l\leq t\leq mid\)的\(g\),然后递归下去即可。



(方法co自这位大佬的博客)

对于\(g(e,t)\),我们可以考虑把它化为卷积的形式进行更新。

令\(mid=mid+1\),对于\(g(e,mid-1)\),我们有\(g(e,mid-1)+=\sum\limits_{i=0}^{r-mid+1}p_{e,i+1}\cdot f(e,mid+i)\)

我们把\(f\)数组反转,\(g(e,mid-1)+=\sum\limits_{i=0}^{r-mid+1}p_{e,i+1}\cdot f(e,r-i)\)。

在映射一下:\(g(e,mid-1)+=\sum\limits_{i=0}^{r-mid+1}p^{\prime}_{e,i}\cdot f^\prime(e,r-mid-i)\)。

即:\(g(e,mid-x)+=\sum\limits_{i=0}^{r-mid+1}p^{\prime}_{e,i}\cdot f^\prime(e,r-(mid-x)-i-1)\)

用\(ans(r-(mid-x)-1)\)来更新\(g(mid-x)\),即用\(ans(r-t-1)\)来更新\(g(t)\)。

代码实现

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#define MAXN 1<<30
typedef long long LL;
const int N=100005;
using namespace std;
inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;}

const double pi=acos(-1);
struct Z{
    double r,i;
    Z(double _r=0,double _i=0){r=_r,i=_i;}
    Z operator + (const Z &a)const{return Z(r+a.r,i+a.i);}
    Z operator - (const Z &a)const{return Z(r-a.r,i-a.i);}
    Z operator * (const Z &a)const{return Z(r*a.r-i*a.i,r*a.i+i*a.r);}
    Z operator / (const double &a)const{return Z(r/a,i/a);}
    Z operator /= (const double &a) {return *this=Z(r/a,i/a);}
};
void FFT(Z *a,int x,int K){
    static int rev[N],lst;
    int n=1<<x;
    if(n!=lst){
        for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<x-1);
        lst=n;
    }
    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){
        int tmp=i<<1;
        Z wn(cos(pi/i),sin(pi*K/i));
        for(int j=0;j<n;j+=tmp){
            Z w(1,0);
            for(int k=0;k<i;k++,w=w*wn){
                Z x=a[j+k],y=w*a[i+j+k];
                a[j+k]=x+y,a[i+j+k]=x-y;
            }
        }
    }
    if(K==-1)for(int i=0;i<n;i++)a[i]/=n;
}
Z a[N],b[N];

int n,m,T,X;
double p[105][20005];
struct node{int x,y,z;}s[105];
double mp[55][55],f[55][N],g[105][N];
void Floyd(){
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
}
void Cal(int l,int mid,int r){
    int len=r-l;
    for(int j=1;j<=m;j++){
        int x=ceil(log2(len+r-mid));
        fill(a,a+(1<<x),0),fill(b,b+(1<<x),0);
        for(int i=0;i<r-mid+1;i++)a[i].r=f[s[j].y][r-i];
        for(int i=0,lim=min(T,len);i<lim;i++)b[i].r=p[j][i+1];
        FFT(a,x,1),FFT(b,x,1);
        for(int i=0;i<(1<<x);i++)a[i]=a[i]*b[i];
        FFT(a,x,-1);
        for(int i=mid-1;i>=l;i--)g[j][i]+=a[r-i-1].r;
    }
}
void Binary(int l,int r){
    if(l==r){
        for(int i=1;i<=m;i++)
            f[s[i].x][l]=min(f[s[i].x][l],s[i].z+g[i][l]);
        return;
    }
    int mid=l+r>>1;
    Binary(mid+1,r);
    Cal(l,mid+1,r);
    Binary(l,mid);
}
int main(){
    n=Getint(),m=Getint(),T=Getint(),X=Getint();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i^j)mp[i][j]=MAXN;
    for(int i=1;i<=m;i++){
        int x=Getint(),y=Getint(),z=Getint();
        s[i]=(node){x,y,z};
        mp[x][y]=min(mp[x][y],1.0*z);
        for(int j=1;j<=T;j++)p[i][j]=(double)Getint()/100000;
    }
    Floyd();
    for(int j=T+1;j<=2*T;j++)f[n][j]=X;
    for(int i=1;i<n;i++){
        for(int j=0;j<=T;j++)f[i][j]=MAXN;
        for(int j=T+1;j<=2*T;j++)f[i][j]=X+mp[i][n];
    }
    Cal(1,T+1,2*T);
    Binary(0,T);
    printf("%.6f",f[1][0]);
    return 0;
}

原文地址:https://www.cnblogs.com/Emiya-wjk/p/10040948.html

时间: 2024-07-31 22:27:44

Codeforces 553E Kyoya and Train的相关文章

●codeforces 553E Kyoya and Train

题链: http://codeforces.com/problemset/problem/623/E 题解: FFT,DP 题意: 一个有向图,给出每条边的起点u,终点v,费用c,以及花费每种时间的概率P[e][j](表示走第e条边花费时间为j的概率) 现在需要从1号点走到n号点,如果不能在T个单位时间内到达,则达到后还要另外支付X的费用. 求出所需支付的最小期望费用. 先是一个暴力的DP方案: (考虑到每条边的耗时至少为1,可以把状态设为类似分层图的形式) 定义$F[i][t]$为$t$时刻在

【Codeforces553E_CF553E】Kyoya and Train(概率_CDQ分治_FFT)

题目 Codeforces 553E 我为什么要写这道题?因为说到 553 ,你有没有想到 -- 翻译 这个 Kyoya Ootori 怎么看都像是日语名字但是我是真查不出来对应的汉字是什么(好像是什么京屋鳳之类的),方便起见直接认为主人公叫张三. 题目名称:张三和火车 描述 张三想坐火车去学校.有 \(n\) 个火车站和在不同车站间开行的 \(m\) 条单向火车线路.张三现在在 \(1\) 号火车站,学校在 \(n\) 号火车站.他必须买票才能坐火车,并且坐火车也需要花费时间.然而,由于火车存

Codeforces A. Kyoya and Colored Balls(分步组合)

题目描述: Kyoya and Colored Balls time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Kyoya Ootori has a bag with n colored balls that are colored with k different colors. The colors are labeled f

Codeforces Beta Round #8A Train and Peter (string的运用)

Train and Peter Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on CodeForces. Original ID: 8A 64-bit integer IO format: %I64d      Java class name: (Any) Prev Submit Status Statistics Discuss Next Peter likes to travel by train.

codeforces 553A . Kyoya and Colored Balls 组合数学

Kyoya Ootori has a bag with n colored balls that are colored with k different colors. The colors are labeled from 1 to k. Balls of the same color are indistinguishable. He draws balls from the bag one by one until the bag is empty. He noticed that he

Codeforces 553A. Kyoya and Colored Balls

Kyoya Ootori has a bag with n colored balls that are colored with k different colors. The colors are labeled from 1 to k. Balls of the same color are indistinguishable. He draws balls from the bag one by one until the bag is empty. He noticed that he

Codeforces - 814B - An express train to reveries - 构造

http://codeforces.com/problemset/problem/814/B 构造题烦死人,一开始我还记录一大堆信息来构造p数列,其实因为s数列只有两项相等,也正好缺了一项,那就把两种情况构造出来暴力验证对不对就行了. #include<bits/stdc++.h> using namespace std; #define ll long long int n; int s[1005]; int us[1005]; int t[1005]; int ut[1005]; int

Codeforces 553B Kyoya and Permutation

problem 题意 本题题意不太容易看懂.给定一个序列,我们可以把这个序列变成一些循环置换的和.然而这种置换的方法是不止一种的.我们定义一种standard cyclic representation,即每个循环置换中最大的数都在第一个.把得到的循环置换的括号去掉,我们可以得到一个新的序列.定义一个序列,使得它变成置换后再去掉括号得到的新序列和原序列相同,那么称这样的序列是稳定的.给定一个n(序列长度)和k,要求求出所有稳定序列按字典序排序后的第k大序列. 思路 首先我们可以证明,稳定序列是具

找规律 Codeforces Round #309 (Div. 2) A. Kyoya and Photobooks

题目传送门 1 /* 2 找规律,水 3 */ 4 #include <cstdio> 5 #include <iostream> 6 #include <algorithm> 7 #include <cstring> 8 #include <cmath> 9 using namespace std; 10 11 const int MAXN = 1e4 + 10; 12 const int INF = 0x3f3f3f3f; 13 char s