• JYOI 四月普及模拟赛 题解


    这场比赛是本蒟蒻出的。

    第一次出比赛,给原来四中校内的同学做一做,当然很多题不是原创的是搬的,毕竟水平有限

    当然整场比赛还是比较简单的,毕竟难度只到普及,不知道大家自我感觉如何,如果对比赛有什么建议也可以在评论区留言

    题解如下:

    T1 方块游戏(game)

    改编自[NOI2002] 银河英雄传说

    一道水题 说实话挺简单的不知道为啥洛谷是蓝题,我觉得就普及+难度

    数据范围很大,暴力模拟显然是不能直接做出来的我们考虑并查集优化

    这道题实质不就是一道带权并查集对于每个点,分别记录所属链的头结点、该点到头结点的距离以及它所在集合的大小。

    每次合并将y接在x的尾部,改变y头的权值和所属链的头结点,同时改变x的尾节点。

    注意:每次查找的时候也要维护每个节点的权值。(很重要

    每次查询时计算两点的权值差。标程放在下面,这应该很详细了,看下一题吧

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #define For(i,m,n) for(int i=m;i<=n;i++)
    #define sc scanf
    #define pr printf
    const int N = 1e5 + 10;
    using namespace std;
    int n,m,k,t,p[N],ret[N],cnt[N];
    char op[2];
    int find(int x)
    {
        if(x == p[x])return x;
        int y = p[x];
        p[x] = find(p[x]);
        ret[x] += ret[y];
        return p[x];
    }
    int main()
    {
        freopen("game.in", "r", stdin);
        freopen("game.out", "w", stdout);  
        sc("%d",&n);
        For(i,1,n)p[i] = i,cnt[i] = 1;
        For(i,1,n)
        {
            int j;
            sc("%s%d",op,&j);
            if(op[0] == 'M')
            {
                sc("%d",&k);
                int x = find(j),y = find(k);
                p[x] = y;
                ret[x] += cnt[y];
                cnt[y] += cnt[x];
            }
            else
            {
                find(j);
                pr("%d
    ",ret[j]);
            }
        }
        return 0;
    }

    T2 城市联盟(city)

    原题来自一本通题目友好城市

    题目有两个条件:1.每个城市只能开辟一个高速 2.所有的铁路之间不能相交、

    求最多可以建多少条铁路

    先讲O(N2)的做法

    我们可以这样想,只固定考虑一个阵营的坐标

    容易发现 我们要想让铁路不相交,就必须让一个阵营的所有城市排序后,求出另外一边的LCS(最长上升子序列),可以用反证法

    然后O(N log N)的做法 就是基于二分对LCS进行优化,优化为一个log;

    只不过我数据范围应该大一点——这题才5000,真的是良心,N2都可以过,不想说啥了;

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 5010;
    
    typedef pair<int,int> PII;
    
    int f[N],q[N];
    
    PII a[N];
    int main()
    {
        freopen("city.in","r",stdin);
        freopen("city.out","w",stdout);
        int n;
        cin  >> n;
        for(int i = 0; i < n; ++ i) scanf("%d%d",&a[i].first,&a[i].second);
        sort(a,a + n);
        int len = 0;
        q[0] = 10;
        for(int i = 0; i < n; ++ i)
        {
            int l = 0,r = len;
            while(l < r)
            {
                int mid = l + r  + 1 >> 1;
                if(q[mid] < a[i].second) l = mid;
                else r = mid - 1;
            }
            q[r + 1] = a[i].second;
            len = max(len,r + 1);
        }
        
        cout << len << endl;
        return 0;
        
    
    }//二分优化LCS

    T3 苍穹之路(sky)

    这题我稍微改了下题面

    翻译一下就是:

    给定一个无向图,有n个顶点,m条边,每条边有一个权值t,但当当前走过的边数大于等于了这条路的分值h,这条路就不能再走了。

    求顶点s到终点z所走的最小权值和,若走不到,则输出impossible!

    这道题一看就是个最短路,多了关键字罢了

    标程(伪):

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #define maxn 3000010
    //#define int long long
    #define INF 0x3f3f3f3f
    
    using namespace std;
    
    bool vis[maxn];
    int n,m,s,t,tot,ans,now;
    int Step[maxn],Dis[maxn],h[maxn];
    struct node{int pos,Step,Dis;};
    struct edge{int fr,to,dis,cost,nxt;}e[maxn];
    
    inline int read(){
        int s=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
        return s*w;
    }
    
    void add(int fr,int to,int dis,int cost){
        e[++tot].to=to;e[tot].cost=cost;
        e[tot].dis=dis;e[tot].nxt=h[fr];
        h[fr]=tot;
    }
    
    void spfa(int st){
        memset(Dis,INF,sizeof Dis);
        Dis[st]=Step[st]=0;queue<node> d;//vis[st]=1;
        d.push((node){st,0,0});
        while(!d.empty()){
            node u=d.front();d.pop();//vis[u.pos]=0;
            for(int i=h[u.pos];i != -1;i=e[i].nxt){
                if(u.Step>=e[i].cost) continue;int to=e[i].to;
                if(Dis[to]>u.Dis+e[i].dis||Step[to]>u.Step+1){
                    Dis[to]=u.Dis+e[i].dis,Step[to]=u.Step+1;
                    d.push((node){to,Step[to],Dis[to]});
                }
            }
        }
    }
    
    signed main(){
        freopen("sky.in","r",stdin);
        freopen("sky.out","w",stdout);
        memset(h,-1,sizeof h);
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for(int i=1,fr,to,dis,cost;i<=m;i++){
            scanf("%d%d%d%d",&fr,&to,&dis,&cost);
            add(fr,to,dis,cost);add(to,fr,dis,cost);
        }
        spfa(s);
        if(Dis[t]==INF) printf("bao 0
    ");
        else printf("%d
    ",Dis[t]);
        return 0;
    }

    一场考察较容易基础算法的比赛就这样end

     

    THANKS

  • 相关阅读:
    段间跳转之陷阱门
    段间跳转之中断门
    段间跳转之调用门
    代码段段间跳转流程
    Window内核学习之保护模式基础
    回顾2020,展望2021
    内存管理之堆
    Windows进程间通讯(IPC)----信号量
    线程本地存储(动态TLS和静态TLS)
    Windows进程间通讯(IPC)----套接字
  • 原文地址:https://www.cnblogs.com/yjyl0098/p/14620286.html
Copyright © 2020-2023  润新知