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