Educational Codeforces Round 163 (Rated for Div. 2)
A - Special Characters
解題思路:
一個相同的連續段會貢獻兩個特殊字元,所以答案一定是偶數,找個不同的數分隔開即可。
程式碼:
#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;
void solve()
{
int n;
cin >> n;
if (n & 1)
{
puts("NO");
return;
}
string a = "AA";
string b = "B";
string ans;
n /= 2;
for (int i = 1; i <= n; i++)
{
ans += a + b;
}
puts("YES");
cout << ans << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
B - Array Fix
解題思路:
從左到右找到最後一個\(a_i > a_{i + 1}\),記錄\(idx = i\)。
對於\(1 \sim i\)都進行操作,然後從左到右判斷合法即可。
程式碼:
#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;
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
int idx = -1;
for (int i = 1; i <= n - 1; i++)
{
if (a[i] > a[i + 1])
{
idx = i;
}
}
if (idx == -1)
{
puts("YES");
return;
}
vector<int> ans;
for (int i = 1; i <= idx; i++)
{
int x = a[i];
vector<int> t;
while (x)
{
t.push_back(x % 10);
x /= 10;
}
reverse(t.begin(), t.end());
for (auto c : t)
{
ans.push_back(c);
}
if (a[i] == 0)
{
ans.push_back(0);
}
}
for (int i = idx + 1; i <= n; i++)
{
ans.push_back(a[i]);
}
// cout << ans[0] << endl;
for (int i = 1; i < ans.size(); i++)
{
// cout << ans[i] << endl;
if (ans[i] < ans[i - 1])
{
puts("NO");
return;
}
}
puts("YES");
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
C - Arrow Path
解題思路:
分類討論:
- 右邊為\(>\):向右走兩格。
- 右邊為\(<\):不動。
- 下邊為\(>\):向右下走。
- 下邊為\(<\):向左下走。
- 左邊為\(<\):向左走兩格。嘗試舉例後發現沒必要。
- 左邊為\(>\):不動。
從\((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;
void solve()
{
int n;
cin >> n;
vector<string> g(3);
vector<vector<int>> dp(6, vector<int>(n + 10, 0));
for (int i = 1; i <= 2; i++)
{
cin >> g[i];
g[i] = ' ' + g[i];
}
dp[1][1] = 1;
for (int j = 1; j <= n; j++)
{
for (int i = 1; i <= 2; i++)
{
if (i == 1)
{
if (g[i + 1][j] == '>')
{
dp[i + 1][j + 1] |= dp[i][j];
}
else
{
dp[i + 1][j - 1] |= dp[i][j];
}
if (g[i][j + 1] == '>')
{
dp[i][j + 2] |= dp[i][j];
}
}
else
{
if (g[i - 1][j] == '>')
{
dp[i - 1][j + 1] |= dp[i][j];
}
else
{
dp[i - 1][j - 1] |= dp[i][j];
}
if (g[i][j + 1] == '>')
{
dp[i][j + 2] |= dp[i][j];
}
}
}
}
if (dp[2][n])
{
puts("YES");
}
else
{
puts("NO");
}
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
D - Tandem Repeats?
解題思路:
列舉合法串的長度,然後列舉串的起點。
舉例:\(abcabda\)。
假設我們一半長度為\(3\),對於\(abc,abd\)是不合法的,那麼從\(b\)開始,也就是\(bca,bda\)一定也是不合法的。
程式碼:
#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;
void solve()
{
string s;
cin >> s;
int n = s.size();
s = ' ' + s;
int ans = 0;
for (int len = n / 2; len > 0; len--)
{
int cnt = 0;
for (int i = 1; i + len <= n; i++)
{
if (s[i] == '?' || s[i + len] == '?' || s[i] == s[i + len])
{
cnt++;
if (cnt == len)
{
ans = max(ans, cnt);
break;
}
}
else
{
cnt = 0;
}
}
}
cout << ans * 2 << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
E - Clique Partition
解題思路:
因為\((i,j)\)相近的兩個數,\(abs(i - j)\)小,所以應該是一個一個連續區間中的數為一個團。
\((1, 2,3,4,5,6,7,8,9,10),k = 8\)。
\(abs(1 - 9)=8,a_1 \neq a_9\),所以理論上,相隔\(8\)的兩個數不會在一個團中。同理可推廣到\(k\)。
考慮能否讓\(abs(i - j) < k\)的數都在一個團中。
考慮\(abs(i - j)\)較大的點對,由於下標差已經較大,我們需要讓點權差儘量小。
對於\((1, 8)\),\(abs(1-8)=7\),所以\(a_1 - a_8 = 1\)才能使二者符合連邊條件。
嘗試後發現,最平衡的方法為
所以,從左到右,每\(k\)個這樣進行構造,最後多出不足\(k\)個的,就按照剩餘個數進行構造。
程式碼:
#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 N = 110;
int ans;
int a[N];
int c[N];
void dfs(int i, int n, int k, int id)
{
if (i > n)
{
return;
}
ans = id;
// 當前團中的點數
int num = min(n - i + 1, k);
int cur = i;
// 1 2 3 4
// 4 3 2 1
for (int j = i + num / 2 - 1; j >= i; j--)
{
a[j] = cur++;
c[j] = id;
}
// 5 6 7 8
// 8 7 6 5
for (int j = i + num - 1; j >= i + num / 2; j--)
{
a[j] = cur++;
c[j] = id;
}
dfs(i + num, n, k, id + 1);
}
void solve()
{
int n, k;
cin >> n >> k;
dfs(1, n, k, 1);
for (int i = 1; i <= n; i++)
{
cout << a[i] << " \n"[i == n];
}
cout << ans << "\n";
for (int i = 1; i <= n; i++)
{
cout << c[i] << " \n"[i == n];
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
F - Rare Coins
解題思路:
區間內金幣有\(g_1\)個,銀幣有\(s_1\)個。區間外有金幣\(g_2\)個,銀幣\(s_2\)個。
我們設區間內有\(a\)個銀幣為\(1\),區間外有\(b\)個銀幣為\(0\)。
其中,\((g_2 + s_2-g_1+1 \leq a + b\leq s1 + s2)\)。
範德蒙德卷積:
所以:
我們已經求出了所有區間內價值大於區間外價值的情況,最後記得乘上\((\frac{1}{2})^{s_1 + s_2}\)的逆元。
程式碼:
#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;
const int N = 1e6 + 10;
ll f[N];
ll inv[N];
ll qmi(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
{
res = res * a % mod;
}
b >>= 1;
a = a * a % mod;
}
return res;
}
void init()
{
const int n = 1e6;
f[0] = inv[0] = 1;
for (int i = 1; i <= n; i++)
{
f[i] = f[i - 1] * i % mod;
}
inv[n] = qmi(f[n], mod - 2);
for (int i = n - 1; i >= 1; i--)
{
inv[i] = inv[i + 1] * (i + 1) % mod;
}
}
ll C(ll a, ll b)
{
if (a < 0 || b < 0 || a < b)
return 0;
return (f[a] * inv[b] % mod) * (inv[a - b]) % mod;
}
void solve()
{
int n, q;
cin >> n >> q;
vector<array<ll, 2>> s(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> s[i][0];
s[i][0] += s[i - 1][0];
}
for (int i = 1; i <= n; i++)
{
cin >> s[i][1];
s[i][1] += s[i - 1][1];
}
const ll m = s[n][1];
vector<ll> pre(m + 1);
for (int i = 0; i <= m; i++)
{
pre[i] = C(m, i) % mod;
}
for (int i = 1; i <= m; i++)
{
pre[i] = (pre[i] + pre[i - 1]) % mod;
}
ll d = qmi(qmi(2, m), mod - 2) % mod;
auto get = [&](ll l, ll r) -> ll
{
if (l > r)
{
return 0;
}
return pre[m] - (l >= 1 ? pre[l - 1] : 0) + mod;
};
while (q--)
{
int l, r;
cin >> l >> r;
ll g1 = s[r][0] - s[l - 1][0];
ll s1 = s[r][1] - s[l - 1][1];
ll g2 = s[n][0] - g1;
ll s2 = s[n][1] - s1;
// g1 + a > g2 + s2 - b
// a + b >= g2 + s2 - g1 + 1
// g2 + s2 - g1 + 1 ~ s1 + s2
// C(s1, a) * C(s2, b) -> C(s1 + s2, a + b) (g2 + s2 - g1 + 1 <= a + b <= s1 + s2)
// m = s1 + s2
// cout << g2 + s2 - g1 + 1 << ' ' << m << endl;
cout << (get(g2 + s2 - g1 + 1, m) * d) % mod << ' ';
}
cout << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
init();
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}