Update:
G2可以用记忆化过,
口胡下为什么可以过(问了dalao):
首先答案是sqrt(n)种,二分的路径就是sqrt(n)*log(n)
再来一个n,总的复杂度大约是n * sqrt(n) * log(n)
F题属于思维,这个k就按分成两段和三段进行考虑,其他k大于3的都可以转化成二段或者三段。
不要用unordered_map!
A题: Maximize?
题目大意:
给你一个整数 x, 要求你找出任意一个 y ,。使得
最大。
思路一:暴力
数据范围小,直接暴力。
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
int x; cin >> x;
int res = 0, id = 1;
for (int y = 1; y < x; y ++ ) {
if (__gcd(x, y) + y > res) {
res = __gcd(x, y) + y;
id = y;
}
}
cout << id << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int tt; cin >> tt;
while (tt -- ) solve();
return 0;
}
思路二 :动脑子
我们只要令 y = x - 1,那么就可以使得原式子的值为 x。
所以输出 x - 1即可。
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
int x; cin >> x;
cout << x - 1 << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int tt; cin >> tt;
while (tt -- ) solve();
return 0;
}
B题: Prefiquence
题目大意:
给你两个二进制字符串 𝑎 和 𝑏 。二进制字符串是由字符 "0 "和 "1 "组成的字符串。
您的任务是确定最大可能的数字 𝑘 ,使得长度为 𝑘 的字符串 𝑎 的前缀是字符串 𝑏 的子序列。
思路:贪心
如果b中的要取出来跟a的前缀去匹配,那么是不是越早出现越好?
这样就可以让后面空出更多能够跟a去匹配了。
双指针,时间复杂度
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
int n, m; cin >> n >> m;
int j = 0, ans = 0;
string a, b; cin >> a >> b;
for (int i = 0; i < n; i ++ ) {
while (j < m && b[j] != a[i]) j += 1;
if (j == m) break;
ans += 1, j += 1;
}
cout << ans << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int tt; cin >> tt;
while (tt -- ) solve();
return 0;
}
C题: Assembly via Remainders
题目大意:
给你一个数组 。你的任务是找出任意一个数组
,其中:
- 1≤
≤
代表所有 1≤𝑖≤𝑛 。
%
思路:
我们要构造,如果
比
大的话,根据模的计算,我们是不是可以就直接放入
了?
那我们每次构造出的,都让它等于
,让数组a一直递增,是不是就符合要求了?
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
int n; cin >> n;
vector<int> res;
int last = 600;
res.push_back(last);
for (int i = 1; i < n; i ++ ) {
int x; cin >> x;
res.push_back(res[i - 1] + x);
}
for (auto c : res) cout << c << ' ';
cout << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int tt; cin >> tt;
while (tt -- ) solve();
return 0;
}
D题: Permutation Game
题目大意:
见链接。
思路:
如果我们站的位置是最大的,那么我们就不需要移动了对吧,因为可以一直站在上面得到最大的分数。
否则我们就去下一个位置去看看,能不能获得更多的得分。
遍历的话因为是排列,移动是一个环,所以我们最多的遍历次数是 n
用了set避免重复绕环
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
int n, k, pb, ps; cin >> n >> k >> pb >> ps;
vector<int> p(n + 1), a(n + 1);
int maxv = -1;
for (int i = 1; i <= n; i ++ ) cin >> p[i];
for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = 1; i <= n; i ++ )
if (maxv > a[i]) maxv = a[i];
int score1 = k * a[pb], score2 = k * a[ps];
int now1 = score1, now2 = score2;
int cnt = 0;
unordered_set<int> f1;
while (a[pb] != maxv && cnt < k) {
cnt += 1;
now1 -= (k - cnt) * a[pb];
f1.insert(pb);
pb = p[pb];
if (f1.count(pb)) break;
now1 += (k - cnt) * a[pb];
score1 = max(score1, now1);
}
cnt = 0;
f1.clear();
while (a[ps] != maxv && cnt < k) {
cnt += 1;
now2 -= (k - cnt) * a[ps];
f1.insert(ps);
ps = p[ps];
if (f1.count(ps)) break;
now2 += (k - cnt) * a[ps];
score2 = max(score2, now2);
}
if (score1 > score2) cout << "Bodya\n";
else if (score1 == score2) cout << "Draw\n";
else cout << "Sasha\n";
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int tt; cin >> tt;
while (tt -- ) solve();
return 0;
}
E题: Cells Arrangement
题目大意:
在 n x n 的方格中找到 n 个点,使得它们之间的曼哈顿距离种类最多。
思路:
我们发现样例中有连起来一块的,还有斜着放着的。
可证:先放(1, 1), 再放(1, 2),最后全部斜着放是能取完所有的距离情况的,这是最大,符合要求。
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
void solve() {
int n; cin >> n;
cout << "1 1" << endl;
cout << "1 2" << endl;
for (int i = 3; i <= n; i ++ ) {
cout << i << ' ' << i << endl;
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int tt; cin >> tt;
while (tt -- ) solve();
return 0;
}
F题: Equal XOR Segments
代码:
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 9;
int a[N], pre[N];
map<int, vector<int>> p;
void solve() {
int n, q; cin >> n >> q;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = 1; i <= n; i ++ ) {
pre[i] = pre[i - 1] ^ a[i];
p[pre[i]].push_back(i);
}
while (q -- ) {
int l, r; cin >> l >> r;
if ((pre[r] ^ pre[l - 1]) == 0) {
cout << "YES\n";
continue;
}else {
auto it = lower_bound(p[pre[r]].begin(), p[pre[r]].end(), l);
if (it == p[pre[r]].end()) {
cout << "NO\n";
continue;
}
int t1 = *it;
auto _it = upper_bound(p[pre[l - 1]].begin(), p[pre[l - 1]].end(), t1);
if (_it == p[pre[l - 1]].end()) {
cout << "NO\n";
continue;
}
int t2 = *_it;
if (t1 < r && t2 < r) {
cout << "YES\n";
}else {
cout << "NO\n";
}
}
}
p.clear();
cout << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int tt; cin >> tt;
while (tt -- ) solve();
return 0;
}
G1:Division + LCP (easy version)
题目大意:
见链接。
思路:
极其类似砍木头,是二分答案。
每次我们去找字符串 mid 个长度的前缀在整个字符串中的出现次数,
如果大于等于 k,那么 l = mid,否则 r = mid
找的过程(不会Z函数),用了KMP,
时间复杂度
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
vector<int> nt;
void build(string &s) {
int n = s.size();
vector<int> pi(n);
for (int i = 1; i < n; i ++ ) {
int j = pi[i - 1];
while (j > 0 && s[i] != s[j]) j = pi[j - 1];
if (s[i] == s[j]) j += 1;
pi[i] = j;
}
nt = pi;
}
int KMP(string &t, string &s) {
build(s);
int n = t.size(), m = s.size(), j = 0;
int last = -1e9, ans = 0;
for (int i = 0; i < n; i ++ ) {
while (j > 0 && t[i] != s[j]) j = nt[j - 1];
if (t[i] == s[j]) j += 1;
if (j == m) {
int head = i - m + 1;
if (head >= last + m) {
ans += 1;
last = head;
}
}
}
return ans;
}
void solve() {
int n, k; cin >> n >> k >> k;
string s; cin >> s;
int l = 0, r = n / k + 1;
while (l + 1 != r) {
int mid = l + r >> 1;
string p = s.substr(0, mid);
if (KMP(s, p) >= k) l = mid;
else r = mid;
}
cout << l << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int tt; cin >> tt;
while (tt -- ) solve();
return 0;
}
G2:Division + LCP (hard version)
代码:
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
vector<int> nt;
unordered_map<string, int> p;
void build(string &s) {
int n = s.size();
vector<int> pi(n);
for (int i = 1; i < n; i ++ ) {
int j = pi[i - 1];
while (j > 0 && s[i] != s[j]) j = pi[j - 1];
if (s[i] == s[j]) j += 1;
pi[i] = j;
}
nt = pi;
}
int KMP(string &t, string &s) {
if (p.count(s)) return p[s];
build(s);
int n = t.size(), m = s.size(), j = 0;
int last = -1e9, ans = 0;
for (int i = 0; i < n; i ++ ) {
while (j > 0 && t[i] != s[j]) j = nt[j - 1];
if (t[i] == s[j]) j += 1;
if (j == m) {
int head = i - m + 1;
if (head >= last + m) {
ans += 1;
last = head;
}
}
}
return p[s] = ans;
}
void solve() {
int n, ll, lr; cin >> n >> ll >> lr;
string s; cin >> s;
for (int i = ll; i <= lr; i ++ ) {
int l = 0, r = n / i + 1;
while (l + 1 != r) {
int mid = l + r >> 1;
string temp = s.substr(0, mid);
if (KMP(s, temp) >= i) l = mid;
else r = mid;
}
cout << l << ' ';
}
p.clear();
cout << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int tt; cin >> tt;
while (tt -- ) solve();
return 0;
}