Educational Codeforces Round 116 (Rated for Div. 2)ABCDE题解
比赛地址Educational Codeforces Round 116 (Rated for Div. 2)
容易看出,直接判断首尾字母是否相同即可,因为最后要化成 aba...a 或者 bab...b 形式才行
#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 1e5 + 10;
const int MOD = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}
inline void solve() {
string s; cin >> s;
s[0] = s[s.size() - 1];
cout << s << endl;
}
int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
auto now = clock();
#endif
ios::sync_with_stdio(false), cin.tie(nullptr);
cout << fixed << setprecision(2);
int T; cin >> T;
while (T -- )
solve();
#ifdef DEBUG
cout << "============================" << endl;
cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
return 0;
}
根据题意模拟即可
#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 1e5 + 10;
const int MOD = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}
inline void solve() {
LL n, k; cin >> n >> k;
LL now = 1, ans = 0, tag = 1;
while (now < n) {
ans ++;
now += tag;
tag <<= 1ll;
if (tag > k) {
ans += (n - now + k - 1) / k;
break;
}
}
cout << ans << endl;
}
int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
auto now = clock();
#endif
ios::sync_with_stdio(false), cin.tie(nullptr);
cout << fixed << setprecision(2);
int T; cin >> T;
while (T -- )
solve();
#ifdef DEBUG
cout << "============================" << endl;
cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
return 0;
}
贪心即可
容易看出,比能拼的数多出 \(1\) 即可。
#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 1e5 + 10;
const int MOD = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}
inline void solve() {
LL n, k; cin >> n >> k;
vector<LL> a(n + 1);
for (int i = 1; i <= n; i ++ ) {
cin >> a[i];
a[i] = (LL)pow(10, a[i]);
}
k ++;
LL res = 0;
for (int i = 1; i < n; i ++ ) {
LL d = a[i + 1] / a[i] - 1;
if (k >= d) {
res += a[i] * d;
k -= d;
} else {
res += a[i] * k;
k = 0;
}
}
if (!k) cout << res << endl;
else {
res += a[n] * k;
cout << res << endl;
}
}
int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
auto now = clock();
#endif
ios::sync_with_stdio(false), cin.tie(nullptr);
cout << fixed << setprecision(2);
int T; cin >> T;
while (T -- )
solve();
#ifdef DEBUG
cout << "============================" << endl;
cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
return 0;
}
这题的感觉就是不难,但是代码比较难理,所以以理代码逻辑为主
先说题意,就是给你一个 \(n * m\) 的数字矩阵,然后要求你给每行染成蓝色或者红色。然后再将这个矩阵分为左右两部分,
要求满足以下两点
1、左矩阵中,所有红色格的数字的最小值大于蓝色格子的最大值
2、右矩阵中,所有蓝色格的数字的最小值大于红色格子的最大值
若存在这么一种染色和分割方法,输出具体方案,否则输出不存在。
我们可以先只对左矩阵进行判断,在左矩阵满足的情况下验证右矩阵即可。
那么先解决左矩阵的子问题,贪心来看,一定是红色格的最小值越大越好。不妨我们这样设置,根据每行的最小值的前缀进行从上到下的从小到大的排序,那么就变成了判断左下矩阵的最小值大于左上矩阵的最大值,右上矩阵的最小值大于右下矩阵的最大值。
枚举切割线,然后加亿点预处理就行了,具体看代码
#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 1e5 + 10;
const int MOD = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}
inline void solve() {
int n, m; cin >> n >> m;
vector<vector<int>> g(n + 1, vector<int> (m + 1));
for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) cin >> g[i][j];
vector<vector<int>> pre_max(n + 1, vector<int> (m + 2, 0));//前缀最大值
vector<vector<int>> pre_min(n + 1, vector<int> (m + 2, INF));//前缀最小值
vector<vector<int>> sur_max(n + 1, vector<int> (m + 2, 0));//后缀最大值
vector<vector<int>> sur_min(n + 1, vector<int> (m + 2, INF));//后缀最小值
//预处理前缀后缀最大最小值
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= m; j ++ ) {
pre_max[i][j] = max(pre_max[i][j - 1], g[i][j]);
pre_min[i][j] = min(pre_min[i][j - 1], g[i][j]);
}
for (int j = m; j; j -- ) {
sur_max[i][j] = max(sur_max[i][j + 1], g[i][j]);
sur_min[i][j] = min(sur_min[i][j + 1], g[i][j]);
}
}
for (int j = 1; j < m; j ++ ) {//枚举切割线
vector<PII> Num(n + 1);
for (int i = 1; i <= n; i ++ ) Num[i] = {pre_min[i][j], i};//根据左矩阵的前缀最小值排序
sort(Num.begin() + 1, Num.end());
vector<int> up_r(n + 1, INF), down_r(n + 2);//右上是最小值,右下是最大值
vector<int> up_l(n + 1), down_l(n + 2, INF);//左下是最小值,左上是最大值
//预处理上面的四个数组
for (int i = 1; i <= n; i ++ ) {
int row = Num[i].second;
up_l[i] = max(up_l[i - 1], pre_max[row][j]);
up_r[i] = min(up_r[i - 1], sur_min[row][j + 1]);
}
for (int i = n; i; i -- ) {
int row = Num[i].second;
down_l[i] = min(down_l[i + 1], pre_min[row][j]);
down_r[i] = max(down_r[i + 1], sur_max[row][j + 1]);
}
for (int i = n; i > 1; i -- ) {
//枚举取的红色行数,排序后的第i到第n行都是红色
if (down_l[i] > up_l[i - 1] && up_r[i - 1] > down_r[i]) {//如果满足就是符合题意
cout << "YES" << endl;
vector<char> res(n + 1, 'B');
for (int k = n; k >= i; k -- ) res[Num[k].second] = 'R';
for (int k = 1; k <= n; k ++ ) cout << res[k];
cout << ' ' << j << endl;
return ;
}
}
}
//否则就是不满足
cout << "NO" << endl;
}
int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
auto now = clock();
#endif
ios::sync_with_stdio(false), cin.tie(nullptr);
cout << fixed << setprecision(2);
int T; cin >> T;
while (T -- )
solve();
#ifdef DEBUG
cout << "============================" << endl;
cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
return 0;
}
考虑dp
状态设计 \(dp[i][j]\) 表示有 \(i\) 个人,血量范围是 \(j\) 的方案数
首先考虑最简单的,当每个人第一轮被淘汰的情况,容易看出只能在 \(1到n - 1\) 取值,对于 \(n\) 个人,每人有 \(n - 1\) 种取法,同时考虑到其血量范围,故取 \(dp[n][x] = min(n - 1, x) ^ {n}\)。
如果 \(x < n - 1\) 那么只可能是第一轮就被淘汰完,否则继续考虑
考虑每轮的淘汰人数,由于不能存在最后胜利者,所以我们取每轮淘汰的人数为 \(k\), \(k \in [0, n - 2]\)
然后直接转移即可
\(dp[n][x] = \sum_{k=0}^{n - 2}(n - 1)^k * dp[n - k][x - n + 1] * C_n^i\)
稍微解释一下,由于本轮淘汰了 \(k\) 人,并且本轮所有人扣的血量为 \(n - 1\),所以我们只能从 \(dp[n - k][x - n + 1]\) 中转移,相当于 \(k\) 个人可以分配到 \(1到n - 1\) 的血量,所以是 \((n - 1)^k\),在算上从 \(n\) 个人中选择 \(i\) 个人淘汰 \(C_n^i\),得到转移式。
用记忆化搜索写即可
#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 550;
const int MOD = 998244353;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}
LL dp[N][N], c[N][N];
LL q_pow(LL a, LL b) {
LL res = 1;
for (; b; b >>= 1) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
}
return res;
}
LL dfs(int n, int x) {
if (dp[n][x]) return dp[n][x];
dp[n][x] = q_pow(min(x, n - 1), n);
if (x <= n - 1) return dp[n][x];
for (int i = 0; i <= n - 2; i ++ ) dp[n][x] = (dp[n][x] + q_pow(n - 1, i) * dfs(n - i, x - n + 1) % MOD * c[n][i] % MOD) % MOD;
return dp[n][x];
}
inline void solve() {
int n, x; cin >> n >> x;
for (int i = 0; i <= 500; i ++ ) {
for (int j = 0; j <= i; j ++ ) {
if (i == 0 || j == 0) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % MOD;
}
}
cout << dfs(n, x) << endl;
}
int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
auto now = clock();
#endif
ios::sync_with_stdio(false), cin.tie(nullptr);
cout << fixed << setprecision(2);
// int T; cin >> T;
// while (T -- )
solve();
#ifdef DEBUG
cout << "============================" << endl;
cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
return 0;
}