• 18.8.29 考试总结


    这道题就是分层图最短路啊啊啊啊啊啊啊 可惜我之前没写过 然后就很zz的没搞出来

    dis[ i ][ j ]表示到了第 i 个点经过j个景点的最小距离

    就是开一个超级源汇点 然后S向每个小起点连一条长度为排队时间的边 每个终点向T也连排队长度的边

    然后就很愉快的SFPA了 最后判断答案就是在T处从大到小枚举景点数 如果发现被更新过就可以输出了 耶

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N = 5 * 1e3 + 5;
    int V,m,n,e,l,sink,src,tot,head[N],nex[2 * N],tov[2 * N],val[2 * N];
    ll dis[N][N];
    bool vis[N][N];
    struct sta {
        
        int u,num;
        sta(int u = 0,int num = 0): u(u),num(num) { }
    };
    queue<sta>Q;
    
    void add(int u,int v,int w) {
        
        tot ++;
        nex[tot] = head[u];
        tov[tot] = v;
        val[tot] = w;
        head[u] = tot;
    }
    
    void init( ) {
        
        src = 0,sink = V + 1;
        for(int i = 1;i <= m;i ++) {
            int pos,pp;
            scanf("%d%d",& pos,& pp);
            add(src,pos,pp);
        }
        for(int i = 1;i <= n;i ++) {
            int pos,pp;
            scanf("%d%d",& pos,& pp);
            add(pos,sink,pp);
        }
        for(int i = 1;i <= e;i ++) {
            int u,v,w;
            scanf("%d%d%d",& u,& v,& w);
            add(u,v,w);
        }
    }
    
    void SPFA( ) {
        
        memset(dis,0x3f3f3f,sizeof(dis));
        ll cmp = dis[0][0];
        memset(vis,0,sizeof(vis));
        vis[src][0] = true;
        dis[src][0] = 0;
        Q.push(sta(src,0));
        while(! Q.empty( )) {
            sta a = Q.front( ); Q.pop( );
            vis[a.u][a.num] = false;
            for(int i = head[a.u];i;i = nex[i]) {
                int v = tov[i];
                if(dis[v][a.num + 1] > dis[a.u][a.num] + val[i] && dis[a.u][a.num] + val[i] <= l) {
                    dis[v][a.num + 1] = dis[a.u][a.num] + val[i];
                    if(! vis[v][a.num + 1]) {
                        vis[v][a.num + 1] = true;
                        Q.push(sta(v,a.num + 1));
                    }
                }
            }
        }
        bool tag = true;
        for(int i = V + 1;i >= 1;i --) 
        if(dis[sink][i] != cmp) {
            printf("%d",i - 1);
            tag = false;
            break;
        }
        if(tag)  printf("0");
    }
    
    int main( ) {
        
        freopen("park.in","r",stdin);
        freopen("park.out","w",stdout);
        scanf("%d%d%d%d%d",& V,& m,& n,& e,& l);
        init( );
        SPFA( );
    }

    阿这道题是一道数学公式的题

    可以预先用滑动窗口处理处每个点$i$向右第一个合法的点 记作$r[i]$ 因为从这以后每个点都必定合法

    然后对于某个询问$[L,R]$  因为所有的$r[i]$都是单调不降的 所以可以二分求出在该区间内最后一个合法的位置

    它的答案就是$sum_{i = L}^{pos}(R - i + r[i] - i)cdot (R - r[i] + 1) cdot frac{1}{2}$

    然后化简得

    $ (pos - L + 1) * (R cdot R + R )cdot frac{1}{2} +  sum_{i = L}^{pos}(r[i]  - r[i] cdot r[i] + 2icdot r[i]+(R +1)sum_{i = L}^{pos}i$

    然后发现前面一坨和后面一坨都是可以直接算的 然后剩下的维护一个关于中间一坨的前缀和就可以了。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N = 1e5 + 5;
    int n,m,q,a[N],las[N];
    ll sum[N],r[N];
    
    void init( ) {
        for(int i = 1;i <= n;i ++) scanf("%d",& a[i]);
        int head = 1,tail = 1,tot = 0;
        for(head = 1;head <= n;head ++) {
            while(1) {
                if(tot >= m && tail - head > 1) {
                    r[head] = tail - 1;
                    break;
                }
                if(tail > n) {
                    r[head] = N;
                    break;
                }
                if(! las[a[tail]] && tail <= n)
                    tot ++;
                las[a[tail]] = tail;
                tail ++;
            }
            if(las[a[head]] == head) {
                tot --;
                las[a[head]] = 0;
            }
        }
        for(int i = 1;i <= n;i ++) {
            sum[i] = sum[i - 1] + (r[i] - r[i]*r[i] + 2ll*i*r[i]);
        }
    }
    
    ll find_pos(ll L,ll R) {
        
        ll ans = 0;
        ll rr = R;
        while(L <= rr) {
            ll mid = (L + rr) >> 1;
            if(r[mid] <= R) ans = mid,L = mid + 1;
            else rr = mid - 1;
        }
        return ans;
    }
    
    void solve( ) {
        
        while(q --) {
            
            ll L,R;
            scanf("%I64d%I64d",& L,& R);
            ll pos = find_pos(L,R);
            if(pos == 0) {
                printf("0
    ");
                continue;
            }
            ll R1 = (pos - L + 1) * (R * R + R) ;
            ll R2 = sum[pos] - sum[L - 1];
            ll R3 = (R + 1) * (L + pos) * (pos - L + 1) ;
            printf("%I64d
    ",(R1 + R2 - R3)/2);
        }
    }
    
    int main( ) {
        
        freopen("plan.in","r",stdin);
        freopen("plan.out","w",stdout);
        scanf("%d%d%d",& n,& m,& q);
        init( );
        solve( );
          
    }

    这道题我是讲不清楚了 我下来改题 看代码的时间花费特别多 只能说blutrex大哥代码可读性太差了!!!!

    而且还难得一批 最后几个点还T了 人生第一次被卡常数 呕

    代码(是被卡常的代码 zc大佬和我写的一样结果他就过了!!! 是因为我这份代码太丑了??) 

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ull;
    const int N = 1e3;
    const ull mod = 2000000011;
    int n,m;
    ull q[N],p[N],f[1 << (9 << 1)][65],a3[5];
    struct dat {
        ull a,b;
        dat(ull a = 0,ull b = 0): a(a),b(b) { } 
    }e[N];
    
    ull fast_pow(ull a,ull b) {
        
        ull ans = 1;
        for(;b;b >>= 1,a = a * a % mod)
           if(b & 1) ans = ans * a % mod;
        return ans;
    }
    
    ull inverse(ull a) {
        
        return fast_pow(a,mod - 2);
    }
    
    int main( ) {
        freopen("card.in", "r", stdin);
        freopen("card.out", "w", stdout);
        
        scanf("%d%d",& n,& m);
        ull s = inverse(1ll * 100 * n);
        p[n] = 1;
        a3[0] = 0,a3[1] = inverse(3),a3[2] = 2 * inverse(3) % mod,a3[3] = 1;
        for(int i = 0;i < n;i ++)
           scanf("%I64d",& p[i]),p[i] = p[i] * s % mod,p[n] = (p[n] - p[i] + mod) % mod;
        q[n] = 1;
        for(int i = 0;i < n;i ++)
           scanf("%I64d",& q[i]),q[i] = q[i] * s % mod,q[n] = (q[n] - q[i] + mod) % mod;
        for(int s = (1 << (n << 1)) - 2;s >= 0;s --) {
            e[m] = dat(1,0);
            ull v = 0;
            ull ss = q[n];
            for(int i = 0;i < n;i ++) {
                ss = (ss + q[i] * a3[(s >> (i << 1) & 3)]) % mod;
                if((s >> (i << 1) & 3) < 3)
                v = (v + q[i] * a3[((s >> (i << 1) & 3) ^ 3)] % mod * f[s + (1 << (i << 1))][m]) % mod;
            }
            e[m - 1] = dat(ss * e[m].a % mod,(ss * e[m].b % mod + v) % mod);
            for(int j = m - 2;j >= 0;j --) {
                ull ss = p[n]; v = 0;
                for(int i = 0;i < n;i ++) {
                    ss = (ss + p[i] * a3[(s >> (i << 1) & 3)]) % mod;
                    if((s >> (i << 1) & 3) < 3)
                    v = (v + p[i] * a3[((s >> (i << 1) & 3) ^ 3)] % mod * f[s + (1 << (i << 1))][j + 1]) % mod;
                }
                e[j] = dat(ss * e[j + 1].a % mod,(ss * e[j + 1].b % mod + v) % mod);
            }
            f[s][0] = (e[0].a + e[0].b) % mod * inverse(1 - e[0].a + mod) % mod;
            f[s][m] = (f[s][0] + 1) % mod;
            for(int k = 1;k < m;k ++) f[s][k] = (e[k].a * f[s][m] + e[k].b ) % mod;
        }    
        printf("%I64d",f[0][m] % mod);
    }
  • 相关阅读:
    相似性算法研究
    CNN实战篇-手把手教你利用开源数据进行图像识别(基于keras搭建)
    主流NoSQL数据库的分析与选择
    CentOS7下防火墙相关命令
    Error:(10, 32) java: 程序包org.springframework.xxxl不存在
    Windows下IDEA上传码云push的时候出现push to origin/master was rejected
    SpringBoot配置mybatis使用的两种方式
    SpringBoot+Mybatis-plus测试时碰到的奇怪时区问题
    Java String 在拼接时的编译器优化
    Java Maven项目更新后jdk版本变为1.5
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9557286.html
Copyright © 2020-2023  润新知