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\n", 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\n", 1ll * cnt * (cnt - 1) % MOD * f[n - 2] % MOD);
        else printf("0\n");
    }
    
    return 0;
}
posted @ 2021-07-08 14:36  sunnyday0725  阅读(38)  评论(0编辑  收藏  举报