• 2021暑假算法学习笔记(基础复习)#2


    2021-07-07

    77事变84周年,缅怀先烈,吾辈自强。

    复习了一些数据结构。

    食物链(并查集)

    思路:有三类动物,构成一个小的食物链,我们可以用并查集维护集合,用d[i]表示i号点到根节点的距离,然后因为每个点与根节点只会有三种关系:同类,吃根节点,被根节点吃。所以我们可以用d[i] mod 3的关系来表示这种食物链关系,mod 3余0表示同类,余1表示吃根节点,余2表示被根节点吃,然后这样使得只要两个点在一个集合中,我们就可以通过d[i]的关系来判断两个点的关系。然后如果两个点不在一个集合,说明两者的关系前面没有提到过,所以将其视为真话,把两个点放入一个集合,更新p和d数组关系。

    不同于模板的路径压缩,我们需要维护的东西多了d[i],所以我们要更改路径压缩的代码:

    int find (int x)
    {
        if (p[x] != x)
        {
            int t = find(p[x]);//首先记录下根节点
            d[x] += d[p[x]];//更新d[x]到根节点距离
            p[x] = t;//更新x的父节点
        }
        
        return p[x];
    }
    

    然后有以下code:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 50010;
    
    int p[N];
    int n, k;
    int d[N];
    
    int find (int x)
    {
        if (p[x] != x)
        {
            int t = find(p[x]);
            d[x] += d[p[x]];
            p[x] = t;
        }
        
        return p[x];
    }
    
    int main()
    {
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i ++ ) p[i] = i;
        
        int res = 0;
        while (k -- )
        {
            int r, a, b;
            scanf("%d%d%d", &r, &a, &b);
            if (a > n || b > n) res ++ ;
            else
            {
                int pa = find(a), pb = find(b);
                if (r == 1)
                {
                    if (pa == pb && (d[a] - d[b]) % 3) res ++ ;//不同类
                    else if (pa != pb)
                    {
                        p[pa] = pb;
                        d[pa] = d[b] - d[a];
                    }
                }
                else
                {
                    if (pa == pb && (d[a] - d[b] - 1) % 3) res ++ ;
                    else if (pa != pb)
                    {
                        p[pa] = pb;
                        d[pa] = d[b] + 1 - d[a];
                    }
                }
            }
        }
        
        printf("%d
    ", res);
        
        return 0;
    } 
    
    复习了字符串哈希

    每一位字符看成一个P进制的数,然后ULL存放前缀哈希值自动取模。

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    typedef unsigned long long ULL;
    
    const int N = 100010, P = 131;
    
    ULL h[N], p[N];
    int n, m;
    char s[N];
    
    ULL check(int l, int r)
    {
        return h[r] - h[l - 1] * p[r - l + 1];
    }
    
    int main()
    {
        scanf("%d%d%s", &n, &m, s + 1);
        
        p[0] = 1;
        for (int i = 1; i <= n; i ++ )
        {
            p[i] = p[i - 1] * P;
            h[i] = h[i - 1] * P + s[i];
        }
        
        while (m -- )
        {
            int l1, r1, l2, r2;
            scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
            if (check(l1, r1) == check(l2, r2)) puts("Yes");
            else puts("No");
        }
        
        return 0;
    }
    
    CodeForces-1513B AND Sequences

    思路:

    a1 = a2 & a3 & ... & an = a1 & a2 & ... & an

    a1 & a2 = a3 & ... & an = a1 & a2 & ... & an

    ...

    a1 & a2 & ... & an-1 = an = a1 & a2 & ... & an

    所以得到只需要a1 = an = a1 & a2 & ... & an,中间位置为剩余数字的全排列即可。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long LL;
    
    const int N = 2e5 + 10, MOD = 1e9 + 7;
    
    int t;
    LL num[N];
    LL f[N];
    
    int main()
    {
        scanf("%d", &t);
        
        f[0] = 1;
        for (int i = 1; i < N - 5; i ++ )
            f[i] = f[i - 1] * i % MOD;
        
        while (t -- )
        {   
            LL n, last;
            scanf("%lld", &n);
            
            for (int i = 1; i <= n; i ++ )
            {
                scanf("%lld", &num[i]);
                
                if (i == 1) last = num[i];
                else last &= num[i];
            }
            
            int cnt = 0;
            for (int i = 1; i <= n; i ++ )
                if (num[i] == last)
                    cnt ++ ;
            //这里刚开始忘记成1ll,一直wa。。卡了好久
            //以后建议所有单变量直接开LL
            if (cnt >= 2) printf("%lld
    ", 1ll * cnt * (cnt - 1) % MOD * f[n - 2] % MOD);
            else printf("0
    ");
        }
        
        return 0;
    }
    
  • 相关阅读:
    ubuntu 14.04搭建PHP项目基本流程
    linux下 lvm 磁盘扩容
    LVM基本介绍与常用命令
    Linux LVM逻辑卷配置过程详解
    mysql 5.7中的用户权限分配相关解读!
    linux系统维护时的一些小技巧,包括系统挂载新磁盘的方法!可收藏!
    linux系统内存爆满的解决办法!~
    源、更新源时容易出现的问题解决方法
    NV显卡Ubuntu14.04更新软件导致登录死循环,不过可以进入tty模式
    一些要注意的地方
  • 原文地址:https://www.cnblogs.com/scl0725/p/14985964.html
Copyright © 2020-2023  润新知