CF553E Kyoya and Train

CF553E Kyoya and Train

分治\(FFT\)

先考虑\(dp\)转移,由于从起点出发无法判断一条边的走向,我们考虑从终点转移到起点。

\(dp_{u,t}\)表示在\(t\)时刻到达点\(u\)的最小花费(这里的花费指到达终点的花费,我们所求的答案即为\(dp_{1,0}\))。

枚举出边\(e(u \rightarrow v)\)

\[dp_{u,t}=\min c_e+\sum_{i=1}^T p_{e,j} dp_{v,t+i} \]

直接转移必然\(TLE\),我们观察后面的式子,非常像卷积形式。

那么对于每条边,我们计算出\(g_{e,t}=\sum_{i=1}^T p_{e,i} dp_{v,t+i}\),然后用它去更新\(dp\)值即可。

因此我们考虑卷积,不过我们发现,\(g_{e,t}\)依赖于时间比它更后的\(dp\)值,而\(dp\)值可以用所有出边的\(g\)值计算贡献,所以利用分治\(FFT\)解决。

我们用\([mid+1,r]\)来更新\([l,mid]\)\(g\)值。

\[g_{e,t}=\sum_{i=1}^T p_{e,i} dp_{v,t+i} \]

我们考虑增量:

\[{\Delta_g}_{e,t}=\sum_{i=mid+1}^r p_{e,i-t} dp_{v,i} \]

\(a_i=p_{e,i+1},b_i=dp_{v,r-i}\)

\[{\Delta_g}_{e,t}=\sum_{i=0}^{r-mid-1} a_{mid+i-t} b_{r-mid-1-i} \]

一开始我们只需要预处理\([T,2T)\)\(dp\)值即可。

时间复杂度:\(O(mT \log^2 T)\)

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 55
#define M 105
#define T 20005
#define FT 131075
#define D double
using namespace std;
const int INF=1000000007;
const D pi=acos(-1.0);
struct virt
{
    D x,y;
    virt (D xx=0.0,D yy=0.0)
    {
        x=xx,y=yy;
    }
    virt operator + (virt a)
    {
        return virt(x+a.x,y+a.y);
    }
    virt operator - (virt a)
    {
        return virt(x-a.x,y-a.y);
    }
    virt operator * (virt a)
    {
        return virt(x*a.x-y*a.y,x*a.y+y*a.x);
    }
}G[2][25],a[FT],b[FT];
int s,l,rev[FT];
void Pre()
{
    for (int i=22;i;--i)
    {
        G[0][i]=virt(cos(pi/(1 << i-1)),sin(pi/(1 << i-1)));
        G[1][i]=virt(G[0][i].x,-G[0][i].y);
    }
}
void solve(int n)
{
    s=1,l=0;
    while (s<n)
        s <<=1,++l;
    for (int i=0;i<s;++i)
        rev[i]=(rev[i >> 1] >> 1) | ((i & 1) << l-1);
}
void FFT(virt *a,int t)
{
    for (int i=0;i<s;++i)
        if (i<rev[i])
            swap(a[i],a[rev[i]]);
    for (int mid=1,o=1;mid<s;mid <<=1,++o)
        for (int j=0;j<s;j+=mid << 1)
        {
            virt g(1.0,0.0);
            for (int k=0;k<mid;++k,g=g*G[t][o])
            {
                virt x=a[j+k],y=g*a[j+k+mid];
                a[j+k]=x+y,a[j+k+mid]=x-y;
            }
        }
}
int n,m,t,x,xx;
int mc[N][N];
D dp[N][T << 1],g[M][T << 1];
struct edge
{
    int x,y,cost;
    D t[T << 1];
    D& operator [] (int x)
    {
        return t[x];
    }
}e[M];
template<typename orz>
void ckmin(orz &x,orz y)
{
    x=(x<y)?x:y;
}
void cdq(int l,int r)
{
    if (l==r)
    {
        for (int i=1;i<=m;++i)
            if (e[i].x!=n)
                ckmin(dp[e[i].x][l],e[i].cost+g[i][l]);
        return;
    }
    int mid=(l+r) >> 1;
    if (r<t)
        cdq(mid+1,r);
    int Len1=r-l,Len2=r-mid;
    for (int i=1;i<=m;++i)
        if (e[i].x!=n)
        {
            int u=e[i].x,v=e[i].y;
            for (int j=0;j<Len1;++j)
                a[j]=virt(e[i][j+1],0.0);
            for (int j=0;j<Len2;++j)
                b[j]=virt(dp[v][r-j],0.0);
            solve(Len1+Len2);
            FFT(a,0),FFT(b,0);
            for (int j=0;j<s;++j)
                a[j]=a[j]*b[j];
            FFT(a,1);
            for (int j=l;j<=mid;++j)
                g[i][j]+=a[r-j-1].x/s;
            for (int j=0;j<s;++j)
                a[j]=b[j]=virt();
        }
    cdq(l,mid);
}
int main()
{
    Pre();
    scanf("%d%d%d%d",&n,&m,&t,&x);
    for (int i=0;i<=n;++i)
        for (int j=0;j<=n;++j)
            if (i==j)
                mc[i][j]=0; else
                mc[i][j]=INF;
    for (int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].cost);
        ckmin(mc[e[i].x][e[i].y],e[i].cost);
        for (int j=1;j<=t;++j)
            scanf("%d",&xx),e[i][j]=(D)xx/100000;
    }
    for (int k=1;k<=n;++k)
        for (int i=1;i<=n;++i)
            for (int j=1;j<=n;++j)
                ckmin(mc[i][j],mc[i][k]+mc[k][j]);
    for (int i=1;i<=n;++i)
        for (int j=0;j<(t << 1);++j)
            dp[i][j]=191919191919191919.1919191919;
    for (int i=0;i<(t << 1);++i)
        dp[n][i]=(i<=t)?0:x;
    for (int i=1;i<n;++i)
        for (int j=t;j<(t << 1);++j)
            dp[i][j]=mc[i][n]+x;
    cdq(0,(t << 1)-1);
    printf("%.12lf\n",dp[1][0]);
    return 0;
}
posted @ 2020-12-30 16:03  GK0328  阅读(98)  评论(1编辑  收藏  举报