• 2018.10.4模拟考试


    10.2司机出的考试太太太太毒瘤了...用组里某嘤嘤怪的话说:

    看起来人畜无害,出题比谁都变态。

    由于博主太过蒟(懒)蒻(惰),所以题解就没有啦!

    愿意瞄一眼司机的毒瘤题的各位巨佬请戳我!

    今天猫的题还是很友善的...

    看题请戳我!

    T1 题上说每次必须融合一个马猴值为1的龙珠,因此可以设A=a/b,B=1。

       那么第一种融合即为a/b+1=(a+b)/b

           第二种融合即为1/(b/a+1)=a/(a+b)

       发现两种融合即为分子/(分子+分母)或(分子+分母)/分母

       因此题目可以简化为:对于二元组(a,b),每次操作可以使二元组中的一个数加上另一个数,求到达最

       终状态(c,d)的最少操作数。

       发现整个过程的逆过程类似于求gcd。

    #include<algorithm>//STL通用算法
    #include<bitset>//STL位集容器
    #include<cctype>
    #include<cmath>
    #include<complex>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<deque>//STL双端队列容器
    #include<list>//STL线性列表容器
    #include<map>//STL映射容器
    #include<iostream>
    #include<queue>//STL队列容器
    #include<set>//STL集合容器
    #include<stack>//STL堆栈容器
    #include<utility>//STL通用模板类
    #include<vector>//STL动态数组容器
    #define INF 0x3f3f3f3f
    #define ll long long
    using namespace std;
    ll ans,a,b,k;
    int main()
    {
        freopen("dragon.in","r",stdin);
        freopen("dragon.out","w",stdout);
        scanf("%lld%lld%lld",&a,&b,&k);
        if(!a||!b) {printf("-1
    ");return 0;}
        if(a<b) swap(a,b);
        while(b) {ans+=a/b;a%=b;swap(a,b);}
        printf("%lld
    ",ans*k);
        return 0;
    }

    T2 一道纯思路题。

       把三枚棋子之间的两段距离看做此状态的两个参数。

       由于在某一状态下,其能转移到的状态最少2种,最多3种:

       1.a<--->b<------->c 在此状态下,b可以向左或向右跳,a可以向右跳;

       2.a<------->b<--->c 在此状态下,b可以向左或向右跳,c可以向左跳;

       3.a<----->b<----->c 在此状态下,b可以向左或向右跳。

       发现无论是哪种状态,中间的旗子都能向两边跳,而两侧的棋子却不一定能向中间跳。

       若把每个状态都抽象成一个点,那么以上规律可总结为:

       在一棵树上,每个节点都有2个儿子,却不一定有父亲。(根节点)

       因此此题转化成了树上求两点间路径+统计多余步数分配方案数。

       由于最大步数仅有100步,因此可以直接从起始状态与终止状态分别向上暴跳k步,找到最深的公共节点

       即为LCA。(若无符合条件的节点则无解)

       那么如何统计多余步数的分配方案数呢?

       发现无论如何消耗步数,其方式无非2种:向路径外走或走回路径。可用dp实现。

    #include<algorithm>//STL通用算法
    #include<bitset>//STL位集容器
    #include<cctype>
    #include<cmath>
    #include<complex>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<deque>//STL双端队列容器
    #include<list>//STL线性列表容器
    #include<map>//STL映射容器
    #include<iostream>
    #include<queue>//STL队列容器
    #include<set>//STL集合容器
    #include<stack>//STL堆栈容器
    #include<utility>//STL通用模板类
    #include<vector>//STL动态数组容器
    #define INF 0x3f3f3f3f3f3f3f3f
    #define ll long long
    #define MOD 1000000007
    using namespace std;
    typedef vector<ll> vec;
    ll a,b,c,d,e,f,n,root,dis1=INF,dis2=INF,disrt=-1,disup;
    vec fst[101],lst[101];
    ll dp[101][201][201];
    vec go_up(const vec &x)
    {
        if(x[1]-x[0]==x[2]-x[1]) return x;
        vec tmp(3);
        if(x[1]-x[0]>x[2]-x[1])
            tmp[0]=x[0],tmp[1]=x[1]*2-x[2],tmp[2]=x[1];
        else tmp[0]=x[1],tmp[1]=x[1]*2-x[0],tmp[2]=x[2];
        return tmp;
    }
    ll dfs(ll len,ll l,ll r)
    {
        if(l<root||r<0||len<0) return 0;
        ll &tmp=dp[len][l][r];
        if(tmp>=0) return tmp;tmp=0;
        if(l>r)                                                    //在起点到终点的路径上 
            (tmp+=dfs(len-1,l-1,r))%=MOD,                          //向根走 
            (tmp+=dfs(len-1,l+1,r)*2%MOD)%=MOD;                    //向终点走 
        if(l==r)                                                   //不在起点到终点的路径上 
            (tmp+=dfs(len-1,l-1,r-1))%=MOD,                        //往回走 
            (tmp+=dfs(len-1,l+1,min(disup-dis1+dis2,r+1)))%=MOD,   //往终点走 
            (tmp+=dfs(len-1,l+1,r))%=MOD;                          //往起点走 
        return tmp;
    }
    int main()
    {
        freopen("rabbit.in","r",stdin);
        freopen("rabbit.out","w",stdout);
        scanf("%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e,&f,&n);
        fst[0].push_back(a),fst[0].push_back(b),fst[0].push_back(c);
        lst[0].push_back(d),lst[0].push_back(e),lst[0].push_back(f);
        sort(fst[0].begin(),fst[0].end());
        sort(lst[0].begin(),lst[0].end());
        for(ll i=1;i<=n;i++) fst[i]=go_up(fst[i-1]),lst[i]=go_up(lst[i-1]);
        for(ll i=0;i<=n;i++)
        {
            ll flg=0,j=0;
            for(j=0;j<=n;j++)
                if(fst[i]==lst[j]) {flg=1;break;}
            if(flg) {dis1=i,dis2=j;break;}
        }
        if(dis1+dis2>n) {printf("0
    ");return 0;}
        vec tort=fst[dis1];
        for(ll i=dis1+1;i<=n;i++)
        {
            vec tmp=go_up(tort);
            if(tmp==tort)
            {disrt=i-1-dis1;break;}
            tort=tmp;
        }
        if((dis1+dis2)%2!=n%2) {printf("0
    ");return 0;}
        //若此条件不满足,则在消耗多余步数时无法回到原点 
        disup=(n-dis1-dis2)/2+dis1;
        if(disrt>=0) root=disup-dis1-disrt;
        memset(dp,-1,sizeof(dp));
        dp[0][disup-dis1+dis2][disup-dis1+dis2]=1;
        printf("%lld
    ",dfs(n,disup,disup-dis1));
        return 0;
    }

    T3 又一道思路题...

       然而前15个数据点分5部分分别暴力可拿60分2333

       标算是分治最短路。

       发现每个城市最多5个派送点,一次性横跨城市最多3个,这就是说,在n个派送点中去除最多15个连

       续的派送点会使左右两侧的派送点不连通。换句话说,左右两边的派送点想要互相到达,必须经过中

       间这15个派送点。可以依据这个性质进行分治。

       对于k个城市内的每一个配送点进行一次分治,查出每个询问的l与r到分治点的最短路,取最优即可。

       由于博主已经被第二题虐的死去活来,故仅把std放上来供大佬们参考。

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    const int MaxN = 50010;
    const int MaxM = 200010;
    
    int n, m, k, p, q;
    int belong[MaxM * 10], place_num;
    int sum[MaxM], c[MaxM];
    long long dis[MaxM * 10];
    long long ans[MaxM];
    int vis[MaxM * 10];
    struct edge {
        int to, w;
        edge *next;
    } *last[MaxM], e[MaxM << 1], *edge_cnt = e;
    
    struct query {
        int s, t, i;
    } ask[MaxM], t[MaxM];
    
    void add_edge(int u, int v, int w) {
        *++ edge_cnt = (edge) {v, w, last[u]}, last[u] = edge_cnt;
    }
    
    #include <queue>
    struct data {
        int v;
    
        bool operator < (const data& a) const {
            return dis[v] > dis[a.v];
        }
    } ;
    priority_queue <data > que;
    
    void spfa(int l, int r, int s) {
        for (int i = sum[l - 1] + 1; i <= sum[r]; ++ i) dis[i] = 1ll << 60;
        for (vis[s] = 1, dis[s] = 0, que.push((data) {
        s
    }); que.size(); vis[que.top().v] = 0, que.pop()) {
            for (edge *iter = last[que.top().v]; iter; iter = iter -> next) {
                if (l <= belong[iter -> to] && belong[iter -> to] <= r && (dis[iter -> to] > dis[que.top().v] + iter -> w ? dis[iter -> to] = dis[que.top().v] + iter -> w, 1 : 0)) {
                    if (!vis[iter -> to]) {
                        vis[iter -> to] = 1;
                        que.push((data) {
                            iter -> to
                        });
                    }
                }
            }
        }
    }
    
    void divide(int l, int r, int ql, int qr) {
        if (ql > qr) return ;
        if (r - l + 1 <= k + 5) {
            for (int i = ql; i <= qr; ++ i) {
                spfa(l, r, ask[i].s);
                ans[ask[i].i] > dis[ask[i].t] ? ans[ask[i].i] = dis[ask[i].t] : 0;
            }
            return ;
        }
        int ll = r + l - k >> 1, rr = ll + k + 1;
        int qll = ql, q1, q2;
        for (int i = ql; i <= qr; ++ i) t[i] = ask[i];
        for (int i = ql; i <= qr; ++ i) {
            if (belong[t[i].s] <= ll && belong[t[i].t] <= ll) ask[qll ++] = t[i];
        }
        q1 = qll - 1;
        for (int i = ql; i <= qr; ++ i) {
            if (belong[t[i].s] >= rr && belong[t[i].t] >= rr) ask[qll ++] = t[i];
        }
        q2 = qll - 1;
        for (int i = ql; i <= qr; ++ i) {
            if (!(belong[t[i].s] <= ll && belong[t[i].t] <= ll || belong[t[i].s] >= rr && belong[t[i].t] >= rr)) ask[qll ++] = t[i];
        }
        for (int i = sum[ll] + 1; i <= sum[rr - 1]; ++ i) {
            spfa(l, r, i);
            for (int j = ql; j <= qr; ++ j) {
                ans[ask[j].i] > dis[ask[j].s] + dis[ask[j].t] ? ans[ask[j].i] = dis[ask[j].s] + dis[ask[j].t] : 0;
            }
        }
        divide(l, ll, ql, q1);
        divide(rr, r, q1 + 1, q2);
    }
    
    int main() {
    //    freopen("transport.in", "r", stdin);
    //    freopen("transport.out", "w", stdout);
        scanf("%d%d%d%d%d", &n, &m, &k, &p, &q);
        for (int i = 1; i <= n; ++ i) {
            scanf("%d", c + i);
            for (int j = 1; j <= c[i]; ++ j) belong[++ place_num] = i;
            sum[i] = sum[i - 1] + c[i];
        }
        memset(ans, 63, sizeof ans);
        for (int i = 1; i <= m; ++ i) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add_edge(u, v, w);
            add_edge(v, u, w);
        }
        for (int i = 1; i <= q; ++ i) {
            int s, t;
            scanf("%d%d", &s, &t);
            ask[i] = (query) {
                s, t, i
            };
        }
        divide(1, n, 1, q);
        for (int i = 1; i <= q; ++ i) {
            if (ans[i] > 1000000000) puts("-1");
            else printf("%lld
    ", ans[i]);
        }
        return 0;
    }
  • 相关阅读:
    第三十章 混合线程同步构造
    第二十九章 基元线程同步构造
    第二十八章 I/O限制的异步操作
    第二十七章 计算限制的异步操作
    第二十六章 线程基础
    第二十五章 与WinRT组件互操作
    css实现排序箭头
    js中的toFixed神坑
    react使用中碰到的小问题
    看到一个js中sleep的例子,挺好玩的
  • 原文地址:https://www.cnblogs.com/water-radish/p/9742360.html
Copyright © 2020-2023  润新知