Namomo Spring Camp 2022 Div1 每日一题记录 (Week 12)

Namomo Spring Camp 2022 Div1 每日一题记录 (2022.05.14-2022.05.20)

GCD

题目链接

3 s, 1024 MB

题目描述

给定整数 \(a\)\(m\), 计算整数 \(x\) 的数量,满足 \(0\le x< m\) 同时 \(gcd(a,m)= gcd(a+x,m)\)

输入格式

第一行一个数字 \(T\)

接下来 \(T\)\(2\) 个整数 \(a,m\)

输出格式

T 行,每行一个数,表示答案

样例输入

1
2
3
4
3
4 9
5 10
42 9999999967

样例输出

1
2
3
6
1
9999999966

数据规模

所有数据保证 \(1\le T\le 50,1\le a< m\le 1e10\)

解题思路

复杂度

代码参考

Show code

最大连边数量 (USACO2017FEB Why Did the Cow Cross the Road II, 洛谷 P3657)

题目链接

5 s, 128 MB

题目描述

有两个长度为 \(n\) 的排列 \(A、B\)

其中数的范围均为 \(1 - n\). 若 \(abs(A[i] - B[j]) \le 4\), 则 \(A[i]\)\(B[j]\) 间可以连一条边

现要求在边与边不相交的情况下的最大的连边数量

例如样例中:如果 \(a_1\)\(b_2\) 连边 且 \(a_2\)\(b_1\) 连边,则这两条边相交

数据保证 \(A,B\) 都是一个排列

输入格式

第一行一个整数 \(n\)

接下来 \(n\) 行,每行一个数字 \(a_i\)

接下来 \(n\) 行,每行一个数字 \(b_i\)

样例输入

1
2
3
4
5
6
7
8
9
10
11
12
13
6
1
2
3
4
5
6
6
5
4
3
2
1

样例输出

1
5

数据范围

\(1 \le n \le 10^5\)

解题思路

树状数组优化 LCS

\(f(i,j)\) 表示左边 \([1,i]\), 右边 \([1,j]\) 范围内的最大值,显然是个 LCS 类型的 DP, 有

\[ f(i,j)=\max\{f(i,j-1),f(i-1,j),f(i-1,j-1)+[|a_i-b_j|\leq 4]\} \]

然后用树状数组维护前缀最值优化即可

复杂度

\(O(n\log n)\)

代码参考

Show code

Luogu_P3657view raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/*
* @Author: Tifa
* @Description: From <https://github.com/Tiphereth-A/CP-archives>
* !!! ATTENEION: All the context below is licensed under a
* GNU Affero General Public License, Version 3.
* See <https://www.gnu.org/licenses/agpl-3.0.txt>.
*/
#include <bits/stdc++.h>
using namespace std;
#define _for(i, l, r, vals...) \
for (decltype(l + r) i = (l), i##end = (r), ##vals; i <= i##end; ++i)
template <class T>
bool chkmin(T &a, T b) {
return b < a ? a = b, true : false;
}
template <class T>
bool chkmax(T &a, T b) {
return a < b ? a = b, true : false;
}
const uint32_t OFFSET = 5;
const uint32_t N = 1e5 + OFFSET, M = 2e5 + OFFSET, K = 21;
template <size_t N, typename Tp, bool _clear = false>
class BIT {
protected:
Tp tree[N];
constexpr size_t lowbit(ptrdiff_t x) const { return x & (-x); }

public:
BIT() {}
void clear() { memset(tree, 0, sizeof(tree)); }
void modify(size_t pos, Tp val) {
for (size_t i = pos; i < N; i += lowbit(i)) tree[i] = max(tree[i], val);
}
Tp query(size_t pos) const {
Tp ret = 0;
for (size_t i = pos; i; i = (ptrdiff_t)i - lowbit(i))
ret = max(ret, tree[i]);
return ret;
}
};
BIT<N, int> tr;
int a[N];
int idx_b[N];
int f[N];
auto solve() -> void {
int n;
cin >> n;
_for(i, 1, n) cin >> a[i];
_for(i, 1, n, _) {
cin >> _;
idx_b[_] = i;
}
_for(i, 1, n) {
_for(j, max(1, a[i] - 4), min(n, a[i] + 4)) f[j] = tr.query(idx_b[j] - 1);
_for(j, max(1, a[i] - 4), min(n, a[i] + 4)) tr.modify(idx_b[j], f[j] + 1);
}
cout << tr.query(n);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
solve();
return 0;
}

序列中位数

题目链接

1 s, 1024 MB

题目描述

给定正整数 \(N\), 求出 \(1 \sim N - 1\) 中所有与 \(N\) 互质的数构成的序列 的中位数

我们定义:一个长度为 \(K\) 的序列的中位数是序列中第 \(\lfloor\frac{K + 1}{2}\rfloor\) 大的数字。且两个正整数 \(a\)\(b\) 互质当且仅当 \(gcd(a, b) = 1\)

输入格式

第一行一个正整数 \(T\), 表示数据组数

对于每组数据,一行输入一个正整数 \(N\)

对于所有数据,满足 \(1 \leq T \leq 100\),\(2 \leq N \leq 10^{18}\)

输出格式

对于每组测试数据,输出一行一个正整数,表示答案

样例输入

1
2
3
4
3
6
10
19

样例输出

1
2
3
1
3
9

解题思路

复杂度

代码参考

Show code

选元素 (数据加强版)

题目链接

1 s, 1024 MB

题目描述

给定一个长度为 \(n\) 的整数序列 \(a_1,a_2,…,a_n\)

请你从中挑选 \(x\) 个元素,要求:

  1. 原序列中的每一个长度为 \(k\) 的连续子序列都至少包含一个被选中的元素
  2. 满足条件 \(1\) 的前提下,所选 \(x\) 个元素的相加之和应尽可能大。输出最大可能和

输入格式

第一行包含三个整数 \(n,k,x\)

第二行包含 \(n\) 个整数 \(a_1,a_2,…,a_n\)

输出格式

如果无法满足题目要求,则输出 \(−1\)

否则,输出一个整数,表示所选元素的最大可能和

数据范围

所有测试点满足 \(1≤k,x≤n≤2500, 1≤a_i≤10^9\)

输入样例 1

1
2
5 2 3
5 1 3 10 1

输出样例 1

1
18

输入样例 2

1
2
6 1 5
10 30 30 70 10 10

输出样例 2

1
-1

输入样例 3

1
2
4 3 1
1 100 1 1

输出样例 3

1
100

解题思路

复杂度

代码参考

Show code

最长上升子序列计数 (Bonus)

题目链接

1 s, 1024 MB

本题是 http://oj.daimayuan.top/problem/326 的加强版,差别仅在于 \(n\)\(a_i\) 的取值

题目描述

求最长上升子序列及其长度的问题已经相当普及,本题希望你求解 最长上升子序列的个数

只要有序元组有一个值不同,就称不同。如 \([1, {\color{green}3},{\color{red}3}, 0, 4]\)\([1, {\color{green}3}, 4], [1,{\color{red}3}, 4]\) 算作两个答案

输入格式

输入包含两行,第一行有一个整数 \(n\), 表示序列 \(\{a\}\) 的大小

接下来一行包含 \(n\) 个用空格分隔的整数,依次表示 \(a_1, a_2, \cdots, a_n\)

输出格式

输出最长上升子序列的个数

由于这个值可能很大,你只需要输出其模余 \(10^9 + 7\) 的结果

数据规模

-\(1 \le n \le 4 \times 10 ^ 5\) -\(a_i \in [-10 ^ 8, 10 ^ 8]\)

样例 1 输入

1
2
5
1 3 3 0 4

样例 1 输出

1
2

样例 2 输入

1
2
8
1 2 4 2 4 7 3 4

样例 2 输出

1
5

解释

共包含:

\([1, 2, 4, 7] \times 3\)

\([1, 2, 3, 4] \times 2\)

解题思路

复杂度

代码参考

Show code

LCM 与 GCD (CF1499D)

题目链接

3 s, 1024 MB

题目描述

给定三个正整数 \(x,y,k\), 求满足 \(x \times lcm(a,b) - y \times gcd(a,b) = k\) 的数对 \((a,b)\) 的数量,其中 \(lcm(a,b)\)\(a,b\) 的最小公倍数,\(gcd(a,b)\)\(a,b\) 的最大公约数

\(a \neq b\) 那么 \((a,b)\)\((b,a)\) 是两个不同的数对

输入格式

第一行一个整数 \(t\), 表示数据组数.\((1 \leq t \leq 10^3)\)

接下来 \(t\) 行,每行输入三个整数 \(x,y,k\), 含义如题面所示.\(( 1 \leq x,y,k \leq 10^7 )\)

输出格式

输出 \(t\) 行,每行一个整数,表示满足要求二元对的数量

样例输入

1
2
3
4
5
4
1 1 3
4 2 6
3 3 7
2 7 25

样例输出

1
2
3
4
4
3
0
8

解题思路

简单数论

显然有

\[ \alpha (xpq-y)=k \]

其中 \(p,q\) 互质

然后枚举 \(k\) 的因子之后计算 \(p,q\) 的对数即可

复杂度

\(O(2K+t\sqrt{2k})\), 其中 \(K=10^7\)

代码参考

Show code

CodeForces_1499Dview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*
* @Author: Tifa
* @Description: From <https://github.com/Tiphereth-A/CP-archives>
* !!! ATTENEION: All the context below is licensed under a
* GNU Affero General Public License, Version 3.
* See <https://www.gnu.org/licenses/agpl-3.0.txt>.
*/
#include <bits/stdc++.h>
using namespace std;
using i64 = int64_t;
#define _for(i, l, r, vals...) \
for (decltype(l + r) i = (l), i##end = (r), ##vals; i <= i##end; ++i)
const int N = 2e7 + 5, P = 1.5e6 + 5;
bool vis[N];
int prime[P], cnt_prime;
uint8_t prime_factor_cnt[N];
void init_prime(const int &n = N - 1) {
for (int i = 2; i <= n; ++i) {
if (!vis[i]) {
prime[++cnt_prime] = i;
prime_factor_cnt[i] = 1;
}
for (int j = 1; j <= cnt_prime && i * prime[j] <= n; ++j) {
vis[i * prime[j]] = 1;
prime_factor_cnt[i * prime[j]] = prime_factor_cnt[i];
if (i % prime[j] == 0) break;
++prime_factor_cnt[i * prime[j]];
}
}
}
i64 calc(i64 x, i64 y, i64 k2) {
if ((k2 + y) % x) return 0;
return i64(1) << prime_factor_cnt[(k2 + y) / x];
}
auto solve() -> void {
i64 x, y, k;
cin >> x >> y >> k;
if (k % gcd(x, y)) {
cout << "0\n";
return;
}
i64 ans = 0;
_for(i, 1, (int)sqrt(k)) {
if (k % i) continue;
ans += calc(x, y, k / i);
if (i != k / i) ans += calc(x, y, i);
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
init_prime();
int _t;
cin >> _t;
while (_t--) solve();
return 0;
}

前缀集 (AtCoder abc250e)

题目链接

2 s, 512 MB

题目描述

定义序列 \(a\) 的前缀集 \(S(a, i)\)a[1]..a[i] 这 i 个元素构成的集合

给定两个长为 \(n\) 的序列 \(a, b\)

\(m\) 次询问,每次询问两个位置 i, j

请你判断 \(a\) 的前缀集 \(S(a, i)\)\(b\) 的前缀集 \(S(b, i)\) 是否相同

输入描述

一行一个整数 \(n(n\leq 5\times 10^5)\)

两行,一行 \(n\) 个整数,分别描述 \(a, b(1\leq a_i,b_i\leq 10^9)\)

一行一个整数 \(m(m\leq 5\times 10^5)\)

\(m\) 行,每行两个数 \(i(1\leq i\leq n)\), \(j(1\leq j \leq n)\), 表示询问 \(S(a, i)\)\(S(b, j)\)

输出描述

m 行,如果相同输出 Y, 否则输出 N

样例输入

1
2
3
4
5
6
7
8
9
10
11
5
1 2 3 4 5
1 2 2 4 3
7
1 1
2 2
2 3
3 3
4 4
4 5
5 5

样例输出

1
2
3
4
5
6
7
Y
Y
Y
N
N
Y
N

原题链接

戳我

解题思路

Hash / Set

\(S_A(i)=|\{a_1,a_2,...,a_i\}|\), 那么 \(S(a,i)=S(b,j)\implies S_A(i)=S_B(j)\)

\(S_A(i)=S_B(j)\), 只需事先计算出来 \(a,b\) 去重后当 \(S_A(i)\) 取哪些值时才会相同即可

复杂度

\(O(n+q)\)

代码参考

Show code

AtCoder_abc250eview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/*
* @Author: Tifa
* @Description: From <https://github.com/Tiphereth-A/CP-archives>
* !!! ATTENEION: All the context below is licensed under a
* GNU Affero General Public License, Version 3.
* See <https://www.gnu.org/licenses/agpl-3.0.txt>.
*/
#include <bits/stdc++.h>
using namespace std;
#define _for(i, l, r, vals...) \
for (decltype(l + r) i = (l), i##end = (r), ##vals; i <= i##end; ++i)
#define _run_continue(expressions) \
{ \
expressions; \
continue; \
}
template <class T>
bool chkmin(T &a, T b) {
return b < a ? a = b, true : false;
}
template <class T>
bool chkmax(T &a, T b) {
return a < b ? a = b, true : false;
}
const uint32_t OFFSET = 5;
const uint32_t N = 2e5 + OFFSET, M = 2e5 + OFFSET, K = 21;
int unq_cnt_a[N], unq_cnt_b[N];
vector<int> unq_a, unq_b;
set<int> s;
#define __init__(x) \
unq_##x.reserve(n); \
_for(i, 1, n, _) { \
cin >> _; \
s.insert(_); \
unq_cnt_##x[i] = s.size(); \
if (unq_cnt_##x[i] > unq_cnt_##x[i - 1]) unq_##x.push_back(_); \
}
bool ans[N];
auto __ins__ = [](int x) {
if (s.count(x)) s.erase(x);
else s.insert(x);
};
auto solve() -> void {
int n;
cin >> n;
__init__(a);
s.clear();
__init__(b);
s.clear();
_for(i, 1, min(unq_a.size(), unq_b.size())) {
__ins__(unq_a[i - 1]);
__ins__(unq_b[i - 1]);
ans[i] = !s.size();
}
int q;
cin >> q;
_for(i, 1, q, x, y) {
cin >> x >> y;
if (unq_cnt_a[x] != unq_cnt_b[y]) _run_continue(cout << "No\n");
cout << (ans[unq_cnt_a[x]] ? "Yes\n" : "No\n");
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
solve();
return 0;
}