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;
}