zoukankan      html  css  js  c++  java
  • 【8.29校内测试】【分层图最短路】【数学公式推导?】

    考场上一眼就觉得是$Astar$!赶快拍完又调了半天结果大样例卡成粑粑...所以索很玄学要少用啊...

    考后看到$fyt$的代码简直就crazy叻!!不就是个分层图最短路DP吗!!所以水题刷的不够多啊...

    定义状态$dp[u][k]$表示当前到$u$点,途径了$k$个点能走的最短距离,因为距离要小于$L$当然是越短越好啊!就可以刷表转移了...

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #include<queue>
    #define LL long long
    using namespace std;
    
    LL dp[5005][5005];
    
    int V, M, N, E, S, T;
    LL L;
    
    struct Node {
        int u, cnt;
        Node ( int u = 0, int cnt = 0 ) :
            u ( u ), cnt ( cnt ) { }
    };
    
    struct Edge {
        int v, nex; LL w;
        Edge ( int v = 0, LL w = 0, int nex = 0 ) :
            v ( v ), w ( w ), nex ( nex ) {    }
    } edge[10005];
    
    int stot, h[5005];
    void add ( int u, int v, LL s ) {
        edge[++stot] = Edge ( v, s, h[u] );
        h[u] = stot;
    }
    
    int vis[5005][5005];
    void Spfa ( ) {
        queue < Node > q;
        q.push ( Node ( S, 0 ) );
        memset ( dp, 0x3f3f3f3f, sizeof ( dp ) );
        vis[S][0] = 1; dp[S][0] = 0;
        while ( !q.empty ( ) ) {
            Node x = q.front ( ); q.pop ( );
            int u = x.u, cnt = x.cnt;
            vis[u][cnt] = 0;
            for ( int i = h[u]; i; i = edge[i].nex ) {
                int v = edge[i].v;
                if ( dp[v][cnt+1] > dp[u][cnt] + edge[i].w && dp[u][cnt] + edge[i].w <= L ) {
                    dp[v][cnt+1] = dp[u][cnt] + edge[i].w;
                    if ( !vis[v][cnt+1] ) {
                        vis[v][cnt+1] = 1;
                        q.push ( Node ( v, cnt + 1 ) );
                    }
                }
            }
        }
    }
    
    int main ( ) {
        freopen ( "park.in", "r", stdin );
        freopen ( "park.out", "w", stdout );
        scanf ( "%d%d%d%d%I64d", &V, &M, &N, &E, &L );
        S = 0, T = V + 1;
        for ( int i = 1; i <= M; i ++ )    {
            int s; LL a;
            scanf ( "%d%I64d", &s, &a );
            add ( S, s, a );
        }
        for ( int i = 1; i <= N; i ++ ) {
            int t; LL b;
            scanf ( "%d%I64d", &t, &b );
            add ( t, T, b );
        }
        for ( int i = 1; i <= E; i ++ ) {
            int u, v; LL s;
            scanf ( "%d%d%I64d", &u, &v, &s );
            add ( u, v, s );
        }
        Spfa ( );
        for ( int i = V + 1; i >= 0; i -- ) 
            if ( dp[T][i] <= L ) {
                if ( i ) printf ( "%d", i - 1 );
                else printf ( "0" );
                break;
            }
        return 0;
    }

    数据范围和题意好分块啊...QAQ,大样例欺骗我!!

    正解是推公式,通过部分预处理和部分$O(1)$计算得到,我们发现,所有点满足条件的位置$des[i]$是单调不降的,而且第一个满足了后面一定都满足。所以首先想到每次询问,二分出最后一个$des[i]$在$R$以内的$pos$,$L$到$pos$的贡献都要计算在内。

    然后发现,我们要求的实际上是$sum_{i=L}^{pos}{frac{(des[i]-i+R-i)(R-des[i]+1)}{2}}$,后面的一坨是已经化简过的所有$j-i$的等差数列。

    拆开得到一堆东西,只和$des[i]$和$i$有关的可以$O(n)$预处理,只和$R$有关的可以直接$*(pos-L+1)$,和$i$和$R$有关的用等差数列$O(1)$算,直接得出答案。

    预处理$des[i]$的时候用划窗。

    注意long long!

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    using namespace std;
    
    LL n, m, q, a[100005];
    LL color[100005], Q[100005], des[100005];
    LL sum[100005];
    
    LL erfen ( LL L, LL R ) {
        LL l = L, r = R, ans = L - 1;
        while ( l <= r ) {
            LL mid = ( l + r ) >> 1;
            if ( des[mid] <= R && des[mid] ) ans = mid, l = mid + 1;
            else r = mid - 1;
        }
        return ans;
    }
    
    int main ( ) {
        freopen ( "plan.in", "r", stdin );
        freopen ( "plan.out", "w", stdout );
        scanf ( "%I64d%I64d%I64d", &n, &m, &q );
        for ( LL i = 1; i <= n; i ++ )    scanf ( "%I64d", &a[i] );
        LL h = 1, t = 0, cnt = 0;
        for ( LL i = 1; i <= n; i ++ ) {
            Q[++t] = i; color[a[i]] ++; 
            if ( color[a[i]] == 1 ) cnt ++;
            while ( cnt == m ) {
                des[Q[h]] = t; color[a[Q[h]]] --;
                if ( color[a[Q[h++]]] == 0 ) cnt --;
            }
        }
        for ( LL i = 1; i <= n; i ++ ) {
            LL tmp = -1LL * des[i] * des[i] + des[i] + 1LL * 2 * i * des[i] - 1LL * 2 * i;
            sum[i] = sum[i-1] + tmp;
        }
        for ( LL i = 1; i <= q; i ++ ) {
            LL L, R;
            scanf ( "%I64d%I64d", &L, &R );
            LL pos = erfen ( L, R );
            if ( pos < L ) printf ( "0
    " );
            else {
                LL ans;
                LL tmp1 = 1LL * ( R * R  + R ) * ( pos - L + 1 );
                LL tmp2 = -1LL * ( L + pos ) * ( pos - L + 1 ) * R;
                LL tmp3 = 1LL * ( sum[pos] - sum[L-1] );
                ans = 1LL * ( tmp1 + tmp2 + tmp3 ) / 2;
                printf ( "%I64d
    ", ans );
            }
        }
        return 0;
    }
  • 相关阅读:
    20182330 2019-2020-1 《数据结构与面向对象程序设计》实验四报告
    20182330 2019-2020-1 《数据结构与面向对象程序设计》第四周学习总结
    20182330 2019-2020-1 《数据结构与面向对象程序设计》实验三报告
    20182330 2019-2020-1 《数据结构与面向对象程序设计》第三周学习总结
    20182330 2019-2020-1 《数据结构与面向对象程序设计》实验二报告
    20182330 2019-2020-1 《数据结构与面向对象程序设计》实验一报告
    20182330 2019-2020-1《数据结构与面向对象程序设计》第一周学习总结
    20182326 2019-2020-1 《数据结构与面向对象程序设计》实验六报告
    20182326 2019-2020-1 《数据结构与面向对象程序设计》实验五报告
    2019-2020-26 《数据结构与面向对象程序设计》第6周学习总结
  • 原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9555862.html
Copyright © 2011-2022 走看看