1. 程式人生 > >Codeforces 553E Kyoya and Train

Codeforces 553E Kyoya and Train

truct 數組 rim ani def i++ return b+ 這不

題目大意

鏈接: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;
}

Codeforces 553E Kyoya and Train