CodeTON Round 9 (Div. 1 + Div. 2, Rated, Prizes!)(A~C2)
A - Shohag Loves Mod
思路
假设构造差值是 \(x = 0,1,\dots ,n\) 这样的,那么只要让 \(a_i \equiv x \pmod{i}\) 即可,也就是 \(a_i = i+x\)。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n; i ++) {
cout << i + i - 1 << " \n"[i == n];
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
B. Shohag Loves Strings
思路
其实只要找到形如 aa
和 abc
这种两个一样或三个不一样的就可以,但是很不懂啊,我最开始写得就是用 substr 去截取的,但是一直 \(WA\),后来索性就直接暴力搞了。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve() {
string s;
cin >> s;
int n = s.size();
for (int len : {2, 3, 4, 5}) {
for (int i = 0; i + len <= n; i ++) {
set<string> t;
for (int l = i; l < i + len; l ++) {
for (int r = l; r < i + len; r ++) {
t.insert(s.substr(l, r - l + 1));
}
}
if (t.size() % 2 == 0) {
cout << s.substr(i, len) << "\n";
return;
}
}
}
cout << "-1\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
C1 - Shohag Loves XOR (Easy Version)
思路
题目给定范围 \(\sum n \le 1\times 10^7\),那么直接枚举找 \(y\) 即可。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve() {
int x;
i64 m;
cin >> x >> m;
int ans = 0;
for (int i = 1; i < x; i ++) {
if ((x % i == 0 || (i ^ x) % i == 0 ) && x != (i ^ x) && (i ^ x) <= m) {
ans ++;
}
}
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
C2 - Shohag Loves XOR (Hard Version)
思路
唉唉,数学分类讨论题,感觉这题就应该和 \(D\) 题换个位置,赛时分析了一半看了一眼榜就去写 \(D\) 了,QWQ。
以下要用到的关于异或的性质,不作证明。
\(1、x-y\le x\oplus y \le x + y\)
\(2、x\oplus x = 0\)
\(3、x\oplus y = z \Rightarrow x = z \oplus y\)
设 \(p = x\oplus y\),考虑三种情况,\(p\) 被 \(x\) 整除,\(p\) 被 \(y\) 整除,\(p\) 被 \(\text{lcm}(x,y)\) 整除。
- \(p\) 被 \(x\) 整除的时候:
那么 \(y = p\oplus x,p = k\times x:\)\[\because 1\le y\le m\\\\ \therefore p\oplus x\le m\\\\ 且当 p\oplus x \le p + x \le m 时,p\le m-x\\\\ 那么 x 的倍数有 \left\lfloor\frac{m-x}{x}\right\rfloor 个.\\\\ 这里有两个 x 的倍数需要特殊讨论:\\\\ 一个是0,即当x\le m的时候,0是可取的;\\\\ 另一个是x,当x\le m-x的时候,会取到x为本身的倍数,但是x\oplus x=0<1,所以我们需要去掉.\\\\ 当 p\oplus x \ge p - x > m 时,p > m + x\\\\ 但是 y \le m,\therefore p\not\in(m+x,+\infty)\\\\ \therefore (m-x,m+x] 的范围内最多有两个 x 的倍数,直接枚举即可.\] - \(p\) 被 \(y\) 整除的时候:
- \(x<y:\)
\[\because x > 0\And y>0\\\\ \therefore p=x\oplus y \ne x \And p \ne y\\\\ \therefore 当y>x时,p至少为y的2倍\\\\ 但是 p\le x + y < 2\max(x,y)=2y\\\\ \therefore 此时不存在p.\]- \(x\ge y\)\[此时x\le 1\times 10^6,直接枚举即可. \]
- \(p\) 被 \(\text{lcm}(x,y)\) 整除的时候:
- \(x\ne y:\)\[此时\text{lcm}(x,y)\ge 2\max(x,y)\\\\ 但是由上述推导可知p < 2\max(x,y)\\\\ \therefore 此时不存在 p.\]
- \(x=y:\)
\[当x\le m 时,存在一个p. \] - \(x\ne y:\)
最后答案就是前两个情况的数量减去第三个情况的数量即可。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve() {
int x;
i64 m;
cin >> x >> m;
i64 ans = max(m - x, 0LL) / x + (x <= m);
ans -= (x <= m - x);
for (i64 i = max(m - x, 0LL) + 1; i <= m + x; i++) {
if (i % x == 0 && (i ^ x) <= m && (i ^ x) > 0) {
ans ++;
}
}
for (int i = 1; i <= min<i64>(x, m); i ++) {
if ((i ^ x) % i == 0) {
ans ++;
}
}
cout << ans - (x <= m) << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
D - Shohag Loves GCD
思路
这题也是唐完了。
要使得 \(a_{\gcd(i,j)} \ne \gcd(a_i,a_j)\),且还要让 \(a\) 数组尽可能大,假设 \(a_i\) 是较大的数,那么只要让 \(i\) 的倍数取较小的值即可,但是这里可能会存在问题就是,比如 \(2\) 的倍数 \(4\) 和 \(8\) 又不能填一样的,这里其实就用到了欧拉筛的思想,每个合数都只会被它最小质因数的另一个因子筛掉,这样就可以保证当后面的数对存在 \(\gcd \ne\) 当前 \(i\) 的时候及时退出了,时间复杂度是 \(\mathcal{O}(n)\)。
当然这个题还有另外一种思路,就是对于每一个 \(i\) 来说,都去直接枚举 \(i\) 的倍数,然后后面的数的倍数又会把前面的某些数的倍数给覆盖掉,也能保证每个数的倍数的 \(a_i\) 的 \(\gcd\) 不会与前面重合,时间复杂度是调和级数级别,也就是 \(\mathcal{O}(n\ln n)\)。
不过在 \(cf\) 上貌似两种写法也没有太大的时间差距,跑得都很快就是了。
代码(欧拉筛写法)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve() {
int n, m;
cin >> n >> m ;
set<int> s;
vector<int> a(m + 1);
for (int i = 1; i <= m; i ++) {
cin >> a[i];
}
sort(a.begin() + 1, a.end(), greater<>());
vector<array<int, 2>> ans(n + 1, {0, 0});
ans[1] = {a[1], 1};
vector<int> pr;
for (int i = 2; i <= n; i ++) {
if (!ans[i][0]) {
if (m < 2) {
cout << "-1\n";
return ;
}
pr.emplace_back(i);
ans[i] = {a[2], 2};
}
for (int j = 0; j < pr.size() && pr[j] <= n / i; j ++) {
if (m < ans[i][1] + 1) {
cout << "-1\n";
return;
}
ans[i * pr[j]] = {a[ans[i][1] + 1], ans[i][1] + 1};
if (i % pr[j] == 0) break;
}
}
for (int i = 1; i <= n; i ++) {
cout << ans[i][0] << " \n"[i == n];
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}
代码(枚举倍数)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve() {
int n, m;
cin >> n >> m ;
set<int> s;
vector<int> a(m + 1);
for (int i = 1; i <= m; i ++) {
cin >> a[i];
}
sort(a.begin() + 1, a.end(), greater<>());
vector<array<int, 2>> ans(n + 1, {0, 0});
ans[1] = {a[1], 1};
vector<int> pr;
for (int i = 2; i <= n; i ++) {
if (!ans[i][0]) {
if (m < 2) {
cout << "-1\n";
return ;
}
pr.emplace_back(i);
ans[i] = {a[2], 2};
}
for (int j = i + i; j <= n; j += i) {
if (m < ans[i][1] + 1) {
cout << "-1\n";
return;
}
ans[j] = {a[ans[i][1] + 1], ans[i][1] + 1};
}
}
for (int i = 1; i <= n; i ++) {
cout << ans[i][0] << " \n"[i == n];
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}