Codeforces Round 934 (Div. 2)
A - Destroying Bridges
解題思路:
完全圖每個點的連邊數為\(n - 1\)。
- \(k < n - 1\):都可到達。
- \(k \geq n - 1\):將點\(1\)的邊刪完,只能呆在點\(1\)。
程式碼:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
using ull = unsigned long long;
const int mod = 998244353;
void solve()
{
int n, k;
cin >> n >> k;
if (k >= n - 1)
{
cout << 1 << endl;
}
else
{
cout << n << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
B - Equal XOR
解題思路:
對於每個數字只有三種情況:
- 只出現在\((1, n)\)
- 只出現在\((n + 1, 2 n)\)
- 一個出現在\((1, n)\),另一個出現在\(n + 1, 2n\)
前兩種情況數目肯定是相同的。
我們先用前兩種成對分別填入\(l,r\)中,不夠的再用第三種補,整個過程都是同步的。
程式碼:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
using ull = unsigned long long;
const int mod = 998244353;
void solve()
{
int n, k;
cin >> n >> k;
vector<int> a(2 * n + 2);
for (int i = 1; i <= 2 * n; i++)
{
cin >> a[i];
}
vector<int> l, r;
vector<int> vis(2 * n + 10);
// 2, 3, 4
for (int i = 1; i <= n; i++)
{
vis[a[i]] += 1;
}
for (int i = n + 1; i <= 2 * n; i++)
{
vis[a[i]] += 2;
}
vector<int> ls, rs, t;
for (int i = 1; i <= n; i++)
{
if (vis[a[i]] == 3)
{
t.push_back(a[i]);
}
else if (vis[a[i]] == 2)
{
ls.push_back(a[i]);
}
}
for (int i = n + 1; i <= 2 * n; i++)
{
if (vis[a[i]] == 4)
{
rs.push_back(a[i]);
}
}
sort(ls.begin(), ls.end());
ls.erase(unique(ls.begin(), ls.end()), ls.end());
sort(rs.begin(), rs.end());
rs.erase(unique(rs.begin(), rs.end()), rs.end());
for (int i = 0; i < min(ls.size(), rs.size()) && l.size() < 2 * k; i++)
{
l.push_back(ls[i]);
l.push_back(ls[i]);
r.push_back(rs[i]);
r.push_back(rs[i]);
}
for (int i = 0; i < t.size() && l.size() < 2 * k; i++)
{
l.push_back(t[i]);
r.push_back(t[i]);
}
// int t1 = 0;
// int t2 = 0;
for (auto x : l)
{
cout << x << ' ';
// t1 ^= x;
}
cout << "\n";
for (auto x : r)
{
cout << x << ' ';
// t2 ^= x;
}
cout << "\n";
// if (t1 == t2)
// {
// puts("YES");
// }
// // for (int i = 1; i <= n; i++)
// // {
// // t1 ^= a[i];
// // }
// for (int i = n + 1; i <= 2 * n; i++)
// {
// t2 ^= a[i];
// }
// cout << t1 << ' ' << t2 << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
C - MEX Game 1
解題思路:
出現次數大於\(1\)次的,無論先後手肯定都能搶到。
所以我們按照\(mex\),從小到大優先拿出現次數為\(1\)的。
程式碼:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
using ull = unsigned long long;
const int mod = 998244353;
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
map<int, int> cnt;
vector<bool> vis(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
cnt[a[i]]++;
}
for (auto t : cnt)
{
if (t.se >= 2)
{
vis[t.fi] = true;
}
}
int cur = 0;
while (vis[cur])
{
cur++;
}
for (int i = 1; i <= n; i++)
{
while (vis[cur])
{
cur++;
}
if (cnt[cur] == 1)
{
cnt[cur]--;
vis[cur] = true;
}
else
{
break;
}
while (vis[cur])
{
cur++;
}
if (cnt[cur] == 1)
{
cnt[cur]--;
}
}
int ans = 0;
while (vis[ans])
{
ans++;
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
D - Non-Palindromic Substring
解題思路:
\(len = r - l + 1\):
- \(k = 1\):肯定迴文。
- \(k = len\):單獨判斷
- \(2 \leq k \leq len - 1\):
- \(k\)為奇數:只要整個區間不是\(aba...aba\)這種交叉形式,奇數子串一定都存在。如果\(k = 3\)不存在,意味著整個區間都是\(aba...aba\)這種交叉形式。
- \(k\)為偶數:只要整個區間字元不是都一樣,偶數子串一定都存在。如果\(k = 2\)不存在,意味著整個區間都是一樣的。
注意:本題疑似卡了單雜湊,如果要用雜湊判斷整體是否迴文,建議使用雙雜湊對映。
判斷整體迴文:\(manacher\);雙雜湊
判斷奇數是否存在:
- 思路一:\(f[i]:記錄右側奇偶性相同的下標中,第一個不同的字元的位置\),\((f[l] \leq r || f[l + 1]\leq r)\)。
- 思路二:雜湊判斷\((l, r - 2)和(l + 2, r)\)是否完全相同。
判斷偶數是否存在:
- 思路一:\(f[i]:記錄右側第一個不同的字元的位置\),\((f[l] \leq r)\)。
- 思路二:區間最大最小值相同。
程式碼:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
using ull = unsigned long long;
const int P = 13331;
std::vector<int> manacher(std::string s)
{
std::string t = "#";
for (auto c : s)
{
t += c;
t += '#';
}
int n = t.size();
std::vector<int> r(n);
for (int i = 0, j = 0; i < n; i++)
{
if (2 * j - i >= 0 && j + r[j] > i)
{
r[i] = std::min(r[2 * j - i], j + r[j] - i);
}
while (i - r[i] >= 0 && i + r[i] < n && t[i - r[i]] == t[i + r[i]])
{
r[i] += 1;
}
if (i + r[i] > j + r[j])
{
j = i;
}
}
return r;
}
void solve()
{
int n, q;
cin >> n >> q;
string s;
cin >> s;
auto rad = manacher(s);
string str = s;
s = ' ' + s;
vector<ull> h(n + 1), p(n + 1), h1(n + 10);
p[0] = 1;
for (int i = 1; i <= n; i++)
{
p[i] = p[i - 1] * P;
h[i] = h[i - 1] * P + s[i];
}
reverse(str.begin(), str.end());
str = ' ' + str;
for (int i = 1; i <= n; i++)
{
h1[i] = h1[i - 1] * P + str[i];
}
auto get1 = [&](int l, int r) -> ull
{
return h[r] - h[l - 1] * p[r - l + 1];
};
auto get2 = [&](int l, int r) -> ull
{
return h1[r] - h1[l - 1] * p[r - l + 1];
};
vector<vector<int>> f(n + 1, vector<int>(22)), g(n + 1, vector<int>(22, 1e9));
for (int j = 0; (1 << j) <= n; j++)
{
for (int i = 1; i + (1 << j) - 1 <= n; i++)
{
if (j == 0)
{
f[i][j] = s[i];
}
else
{
f[i][j] = max(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
}
}
}
auto q1 = [&](int l, int r)
{
int len = (r - l + 1);
int k = log(len) / log(2);
return max(f[l][k], f[r - (1 << k) + 1][k]);
};
for (int j = 0; (1 << j) <= n; j++)
{
for (int i = 1; i + (1 << j) - 1 <= n; i++)
{
if (j == 0)
{
g[i][j] = s[i];
}
else
{
g[i][j] = min(g[i][j - 1], g[i + (1 << j - 1)][j - 1]);
}
}
}
auto q2 = [&](int l, int r)
{
int len = (r - l + 1);
int k = log(len) / log(2);
return min(g[l][k], g[r - (1 << k) + 1][k]);
};
while (q--)
{
int l, r;
cin >> l >> r;
ll len = r - l + 1;
ll ans = 0;
// if (len & 1)
// {
// ll t = len / 2;
// if (get1(l, l + t - 1) != get2(n - r + 1, n - (l + t + 1) + 1))
// {
// ans += len;
// }
// }
// else
// {
// ll t = len / 2;
// if (get1(l, l + t - 1) != get2(n - r + 1, n - (l + t) + 1))
// {
// ans += len;
// }
// }
// cout << ans << endl;
if (rad[l + r - 1] <= len)
{
ans += len;
}
if (q1(l, r) != q2(l, r))
{
ll up = len;
if (len & 1)
{
up--;
}
else
{
up -= 2;
}
ll k = up / 2;
ans += (2 + up) * k / 2;
}
if (len > 3 && get1(l, r - 2) != get1(l + 2, r))
{
ll up = len;
if (len & 1)
{
up -= 2;
}
else
{
up--;
}
ll k = up / 2;
ans += (3 + up) * k / 2;
}
cout << ans << "\n";
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}