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

思路

其实只要找到形如 aaabc这种两个一样或三个不一样的就可以,但是很不懂啊,我最开始写得就是用 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. \]

最后答案就是前两个情况的数量减去第三个情况的数量即可。

代码

#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;
}
posted @ 2024-11-28 14:55  Ke_scholar  阅读(4)  评论(0编辑  收藏  举报