1985(952div4)
A. Creating Words
马修得到了长度均为
void solve() {
string a, b;cin >> a >> b;
swap(a[0], b[0]);
cout << a << " " << b << '\n';
}
B. Maximum Multiple Sum
给定整数
. - 小于或等于
的 的倍数之和最大。形式上, 中的 在 的所有可能值中最大。
void solve() {
int n;cin >> n;
int ans = 0, idx = 0;;
for (int i = 2, k = n / i;i <= n;i++) {
if ((k + 1) * k * i / 2 > ans) {
ans = (k + 1) * k * i / 2;
idx = i;
}
}
cout << idx << '\n';
}
C. Good Prefixes
亚历克斯认为,如果存在某个元素可以表示为所有其他元素之和(如果没有其他元素,所有其他元素之和为
亚历克斯有一个数组
#define int long long
void solve() {
int n;cin >> n;
vector<int> a(n + 1);
int sum = 0, mx = -1, ans = 0;
for (int i = 1;i <= n;i++) {
int x;cin >> x;
sum += x;
mx = max(mx, x);
if (sum - mx == mx)ans++;
}
cout << ans << '\n';
}
D. Manhattan Circle
给定一个由'.'和'#'字符组成的
点(
在网格上,属于曼哈顿圆的点集标记为 "#"。求圆心坐标。
将这个图形的下标都存下来,然后取中间即可。
void solve() {
int n, m;cin >> n >> m;
vector<string> s(n + 1);
for (int i = 1;i <= n;i++) {
cin >> s[i];s[i] = ' ' + s[i];
}
set<pair<int, int>>st;
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) {
if (s[i][j] == '#') {
st.insert({i,j});
}
}
}
int mihx = 1e6, mxhx = 0;
int mihy = 1e6, mxhy = 0;
for (auto [x, y] : st) {
mihx = min(mihx, x);
mxhx = max(mxhx, x);
mihy = min(mihy, y);
mxhy = max(mxhy, y);
}
cout << (mihx + mxhx) / 2 << " " << (mihy + mxhy) / 2 << '\n';
}
E. Secret Box
Ntarsis 有一个边长为
恩塔西斯有一个秘密盒子
与所有轴平行。 的每个角都位于一个整数坐标上。
在选择
枚举两维第三维即可确定,确定了一个
#define int long long
void solve() {
int x, y, z, v;cin >> x >> y >> z >> v;
int ans = 0;
for (int i = 1;i <= x;i++) {
for (int j = 1;j <= y;j++) {
int k = v / (i * j);
if (i * j * k != v || k > z)continue;
ans = max(ans, (x - i + 1) * (y - j + 1) * (z - k + 1));
}
}
cout << ans << '\n';
}
F. Final Boss
您正在面对您最喜欢的视频游戏中的最终 Boss。敌人的生命值为
最初,所有攻击都不在冷却时间内。要花多少回合才能打败老板?
显然有技能就放就是最优的,直接二分答案计算最小的回合即可(本题
时间复杂度
注:本题数据计算过程中最大的数据要达到
,会爆 {c++}long long
,可以开{c++}int128
或者当计算结果大于后就直接下一轮
#define int long long
void solve() {
int h, n;cin >> h >> n;
vector<int> a(n + 1), c(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
for (int i = 1;i <= n;i++)cin >> c[i];
__int128_t hh = h;
int l = 1, r = 1e13;
while (l < r) {
int mid = l + r >> 1;
__int128_t sum = 0;
for (int i = 1;i <= n;i++) {
sum += (mid + c[i] - 1) / c[i] * a[i];
}
if (sum >= hh)r = mid;
else l = mid + 1;
}
cout << l << '\n';
}
G. D-Function
让
当
当
即要求
若
同理,位数为
依次类推,位数为
则总方案数为:
答案为
constexpr int mod = 1e9 + 7;
void solve() {
cout << (qpow((10 + k - 1) / k, r) - qpow((10 + k - 1) / k, l) + mod) % mod << '\n';
}
H. Maximize the Largest Component
给定一个 #
单元格出发到其他 #
单元格,方向为上下左右,构成了若干连通块。
{c++}easy version:
可以将某一行或某一列全变为 #
{c++}hard version:
可以将某一行和某一列全变为 #
求最大连通部分的最大可能大小。
Solution
easy version
我的想法:先将所有的连通块找出来,再枚举
代码:
int dx[] = {0,0,1,-1}, dy[] = {1,-1,0,0};
void solve() {
int n, m;cin >> n >> m;
vector<string> s(n + 1);
for (int i = 1;i <= n;i++) {
cin >> s[i];s[i] = ' ' + s[i];
}
map<pair<int, int>, pair<int, int>>vis;
int cnt = 0;//第几个连通块
auto bfs = [&](int sx, int sy) {
int sum = 0;//连通块大小
queue<pair<int, int>>q;cnt++;
q.push({sx,sy});
vis[{sx, sy}] = {cnt,++sum};
while (q.size()) {
auto [x, y] = q.front();q.pop();
for (int i = 0;i < 4;i++) {
int a = x + dx[i], b = y + dy[i];
if (a<1 || b<1 || a>n || b>m || vis.count({a,b}) || s[a][b] == '.')continue;
vis[{a, b}] = {cnt,++sum};q.push({a,b});
}
}
q.push({sx,sy});
vis[{sx, sy}] = {cnt,sum};
map<pair<int, int>, int>mp;
while (q.size()) {
auto [x, y] = q.front();q.pop();
for (int i = 0;i < 4;i++) {
int a = x + dx[i], b = y + dy[i];
if (a<1 || b<1 || a>n || b>m || s[a][b] == '.' || mp.count({a,b}))continue;
if (vis.count({a,b})) {
vis[{a, b}] = {cnt,sum};q.push({a,b});mp[{a, b}] = 1;
}
}
}
};
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) {
if (s[i][j] == '#' && !vis.count({i,j})) {
bfs(i, j);
}
}
}
int ans = 0;
for (auto [x, y] : vis) {
ans = max(ans, y.second);
}
for (int i = 1;i <= n;i++) {
map<int, int>st;
int sum = 0;
for (int j = 1;j <= m;j++) {
if (!vis.count({i,j})) {
sum++;
} else {
if (!st.count(vis[{i, j}].first)) {
sum += vis[{i, j}].second;st[vis[{i, j}].first] = 1;
}
}
if (vis.count({i - 1,j})) {
if (!st.count(vis[{i - 1, j}].first)) {
sum += vis[{i - 1, j}].second;st[vis[{i - 1, j}].first] = 1;
}
}
if (vis.count({i + 1,j})) {
if (!st.count(vis[{i + 1, j}].first)) {
sum += vis[{i + 1, j}].second;st[vis[{i + 1, j}].first] = 1;
}
}
}
ans = max(ans, sum);
}
for (int j = 1;j <= m;j++) {
map<int, int>st;
int sum = 0;
for (int i = 1;i <= n;i++) {
if (!vis.count({i,j})) {
sum++;
} else {
if (!st.count(vis[{i, j}].first)) {
sum += vis[{i, j}].second;st[vis[{i, j}].first] = 1;
}
}
if (vis.count({i ,j - 1})) {
if (!st.count(vis[{i, j - 1}].first)) {
sum += vis[{i, j - 1}].second;st[vis[{i, j - 1}].first] = 1;
}
}
if (vis.count({i ,j + 1})) {
if (!st.count(vis[{i, j + 1}].first)) {
sum += vis[{i, j + 1}].second;st[vis[{i, j + 1}].first] = 1;
}
}
}
ans = max(ans, sum);
}
cout << ans << '\n';
}
当
#
特别多的时候会 TLE
先将整个网格含 #
的用并查集连成若干连通块,再和之前思路一样分别考虑即可。
// 模板整理——并查集
void solve() {
int n, m;
cin >> n >> m;
vector<string> s(n);
for (int i = 0; i < n; i++) {
cin >> s[i];
}
const int N = n * m;
DSU dsu(N);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (i + 1 < n && s[i][j] == '#' && s[i + 1][j] == '#') {
dsu.merge(i * m + j, (i + 1) * m + j);
}
if (j + 1 < m && s[i][j] == '#' && s[i][j + 1] == '#') {
dsu.merge(i * m + j, i * m + j + 1);
}
}
}
vector<int> vis(N, -1);
int ans = 0;
for (int r = 0; r < n; r++) {
int res = 0;
for (int i = 0; i < m; i++) {
if (s[r][i] == '.') {
res++;
}
for (int x = max(0, r - 1); x <= min(n - 1, r + 1); x++) {
if (s[x][i] == '#') {
int u = dsu.find(x * m + i);
if (vis[u] != r) {
vis[u] = r;
res += dsu.size(u);
}
}
}
}
ans = max(ans, res);
}
vis.assign(N, -1);
for (int c = 0; c < m; c++) {
int res = 0;
for (int i = 0; i < n; i++) {
if (s[i][c] == '.') {
res++;
}
for (int y = max(0, c - 1); y <= min(m - 1, c + 1); y++) {
if (s[i][y] == '#') {
int u = dsu.find(i * m + y);
if (vis[u] != c) {
vis[u] = c;
res += dsu.size(u);
}
}
}
}
ans = max(ans, res);
}
cout << ans << "\n";
}
hard version
...