AtCoder Beginner Contest 371
A - Jiro
输入 的大小关系,输出中位数。
手动模拟一下。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
int read()
{
int x = 0; bool f = false; char c = getchar();
while(c < '0' || c > '9') f |= (c == '-'), c = getchar();
while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();
return f ? -x : x;
}
char c, a, b;
int main()
{
scanf(" %c", &c);
scanf(" %c %c", &a, &b);
if(c == '<')
{
if(a == '>' && b == '>') printf("A");
if(a == '<' && b == '>') printf("C");
if(a == '<' && b == '<') printf("B");
}else
{
if(a == '>' && b == '>') printf("B");
if(a == '>' && b == '<') printf("C");
if(a == '<' && b == '<') printf("A");
}
return 0;
}
B - Taro
每家的第一个男孩子被命名为 ,按照出生顺序输出每个孩子所在家庭和性别,判断他是否被命名为 。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
int read()
{
int x = 0; bool f = false; char c = getchar();
while(c < '0' || c > '9') f |= (c == '-'), c = getchar();
while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();
return f ? -x : x;
}
const int N = 105;
int vis[N];
int main()
{
int n = read(), m = read();
int a;
char c;
for(int i = 1; i <= m; ++i)
{
scanf("%d %c", &a, &c);
if(c == 'M' && !vis[a])
{
vis[a] = 1;
printf("Yes\n");
}else printf("No\n");
}
return 0;
}
C - Make Isomorphic
给定两个 个点数的图 ,可以用 的代价删去或加上边 ,问最小的花费使得图 同构。
同构的定义是,存在一个排列 ,使得 中存在边 当且仅当 中存在边 。
发现点数很小,暴力枚举排列 计算代价即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
int read()
{
int x = 0; bool f = false; char c = getchar();
while(c < '0' || c > '9') f |= (c == '-'), c = getchar();
while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();
return f ? -x : x;
}
const int N = 10;
int n, mG, mH;
int visG[N][N], visH[N][N];
int val[N][N];
int ans, now;
int p[N];
int main()
{
ans = 0x7fffffff;
n = read();
mG = read();
for(int i = 1; i <= mG; ++i)
{
int u = read(), v = read();
visG[u][v] = 1;
}
mH = read();
for(int i = 1; i <= mH; ++i)
{
int u = read(), v = read();
visH[u][v] = 1;
}
for(int i = 1; i <= n; ++i)
for(int j = i + 1; j <= n; ++j)
val[i][j] = read();
for(int i = 1; i <= n; ++i) p[i] = i;
do
{
now = 0;
for(int i = 1; i <= n; ++i)
for(int j = i + 1; j <= n; ++j)
{
int u = p[i], v = p[j];
if(u > v) swap(u, v);
if(visG[i][j] ^ visH[u][v]) now += val[u][v];
}
ans = min(ans, now);
}while(next_permutation(p + 1, p + n + 1));
printf("%d\n", ans);
return 0;
}
D - 1D Country
有 个位置 ,每个位置有 个人,每次询问位于 位置中的人的个数。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
int read()
{
int x = 0; bool f = false; char c = getchar();
while(c < '0' || c > '9') f |= (c == '-'), c = getchar();
while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();
return f ? -x : x;
}
const int N = 6e5 + 5;
int n, q, nn, m;
int X[N], L[N], R[N], a[N], b[N];
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
ll sum[N << 2];
void update(int k, int l, int r, int pos, int val)
{
if(l == r){ sum[k] += val; return ; }
int mid = (l + r) >> 1;
if(pos <= mid) update(ls(k), l, mid, pos, val);
else update(rs(k), mid + 1, r, pos, val);
sum[k] = sum[ls(k)] + sum[rs(k)];
}
ll query(int k, int l, int r, int L, int R)
{
if(L <= l && r <= R) return sum[k];
int mid = (l + r) >> 1;
if(R <= mid) return query(ls(k), l, mid, L, R);
if(L > mid) return query(rs(k), mid + 1, r, L, R);
return query(ls(k), l, mid, L, R) + query(rs(k), mid + 1, r, L, R);
}
int main()
{
n = read();
for(int i = 1; i <= n; ++i) X[i] = read(), b[++m] = X[i];
for(int i = 1; i <= n; ++i) a[i] = read();
q = read();
for(int i = 1; i <= q; ++i)
{
L[i] = read(), b[++m] = L[i];
R[i] = read(), b[++m] = R[i];
}
sort(b + 1, b + m + 1);
nn = unique(b + 1, b + m + 1) - (b + 1);
for(int i = 1; i <= n; ++i) X[i] = lower_bound(b + 1, b + nn + 1, X[i]) - b;
for(int i = 1; i <= q; ++i)
{
L[i] = lower_bound(b + 1, b + nn + 1, L[i]) - b;
R[i] = lower_bound(b + 1, b + nn + 1, R[i]) - b;
}
for(int i = 1; i <= n; ++i) update(1, 1, nn, X[i], a[i]);
for(int i = 1; i <= q; ++i) printf("%lld\n", query(1, 1, nn, L[i], R[i]));
return 0;
}
E - I Hate Sigma Problems
给定序列 ,求 的所有子序列的不同数值的种类数和。
考虑扫描线,每次扩展右端点,维护所有左端点的答案,记 表示值 上一次出现的位置,那么对于 , 是区间 中的新数,对于这些左端点加 即可。
线段树维护一下区间加,求全局和即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
int read()
{
int x = 0; bool f = false; char c = getchar();
while(c < '0' || c > '9') f |= (c == '-'), c = getchar();
while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();
return f ? -x : x;
}
const int N = 2e5 + 5;
int n, a[N], last[N];
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
ll sum[N << 2], lazy[N << 2], len[N << 2];
void pushdown(int k)
{
if(lazy[k])
{
sum[ls(k)] += len[ls(k)] * lazy[k];
sum[rs(k)] += len[rs(k)] * lazy[k];
lazy[ls(k)] += lazy[k];
lazy[rs(k)] += lazy[k];
lazy[k] = 0;
}
}
void build(int k, int l, int r)
{
len[k] = r - l + 1;
if(l == r) return ;
int mid = (l + r) >> 1;
build(ls(k), l, mid), build(rs(k), mid + 1, r);
}
void update(int k, int l, int r, int L, int R, int val)
{
if(L <= l && r <= R)
{
lazy[k] += val;
sum[k] += len[k] * val;
return ;
}
pushdown(k);
int mid = (l + r) >> 1;
if(L <= mid) update(ls(k), l, mid, L, R, val);
if(R > mid) update(rs(k), mid + 1, r, L, R, val);
sum[k] = sum[ls(k)] + sum[rs(k)];
}
ll query(int k, int l, int r, int L, int R)
{
if(L <= l && r <= R) return sum[k];
pushdown(k);
int mid = (l + r) >> 1;
if(R <= mid) return query(ls(k), l, mid, L, R);
if(L > mid) return query(rs(k), mid + 1, r, L, R);
return query(ls(k), l, mid, L, R) + query(rs(k), mid + 1, r, L, R);
}
int main()
{
n = read();
ll ans = 0;
build(1, 1, n);
for(int i = 1; i <= n; ++i)
{
a[i] = read();
update(1, 1, n, last[a[i]] + 1, i, 1);
last[a[i]] = i;
ans += sum[1];
}
printf("%lld\n", ans);
return 0;
}
F - Takahashi in Narrow Road
有 个人站在一排位置上,第 次命令第 个人到达 位置,人与人之间不会站在同一位置,也不会跨过对方,也就是让第 个人到达第四个人所在的位置,需要第二三四个人都向右移动一些步。问最少需要多少步能完成所有命令,命令必须按顺序完成。
发现一个人会把其他人推到某个位置,然后排成连续的一列,如果位置很少的话可以考虑区间覆盖,区间求和的一系列操作,但是 的位置很可能会都被到达过,空间不允许。
若设 ,那么排成一列的人会在同一个位置。
设 ,不妨设 ,找到最大的 满足 ,,那么第 到第 个人就是完成此次命令需要挪步的人,总步数为 ,同时将这 个人的位置更新为 。
发现对于每个命令,每次最多出现一个新位置,空间允许。
先离散化,线段树维护每一段区间有多少人,所有人的位置之和,快速找到第 个所在位置,找到在第 个位置及之前的人的个数,区间清空,单点加。
线段树开4倍空间!!!
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
int read()
{
int x = 0; bool f = false; char c = getchar();
while(c < '0' || c > '9') f |= (c == '-'), c = getchar();
while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();
return f ? -x : x;
}
const int N = 6e5 + 5;
int n, Q;
int X[N], x[N], b[N], T[N], G[N], g[N];
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
ll lazy[N << 2], sum[N << 2], cnt[N << 2]; // 区间赋0标记
void pushup(int k)
{
sum[k] = sum[ls(k)] + sum[rs(k)];
cnt[k] = cnt[ls(k)] + cnt[rs(k)];
}
void pushdown(int k)
{
if(lazy[k])
{
sum[ls(k)] = sum[rs(k)] = 0;
cnt[ls(k)] = cnt[rs(k)] = 0;
lazy[ls(k)] = lazy[rs(k)] = 1;
lazy[k] = 0;
}
}
void update1(int k, int l, int r, int pos, int Size)
{
if(l == r)
{
sum[k] += 1ll * Size * b[pos];
cnt[k] += Size;
return ;
}
pushdown(k);
int mid = (l + r) >> 1;
if(pos <= mid) update1(ls(k), l, mid, pos, Size);
else update1(rs(k), mid + 1, r, pos, Size);
pushup(k);
}
void update2(int k, int l, int r, int L, int R)
{
if(L <= l && r <= R)
{
sum[k] = cnt[k] = 0;
lazy[k] = 1;
return ;
}
pushdown(k);
int mid = (l + r) >> 1;
if(L <= mid) update2(ls(k), l, mid, L, R);
if(R > mid) update2(rs(k), mid + 1, r, L, R);
pushup(k);
}
pair<ll, ll> query(int k, int l, int r, int L, int R)
{
if(L <= l && r <= R) return pair<ll, ll>(sum[k], cnt[k]);
pushdown(k);
int mid = (l + r) >> 1;
if(R <= mid) return query(ls(k), l, mid, L, R);
if(L > mid) return query(rs(k), mid + 1, r, L, R);
pair<ll, ll> s1 = query(ls(k), l, mid, L, R), s2 = query(rs(k), mid + 1, r, L, R);
return pair<ll, ll>(s1.first + s2.first , s1.second + s2.second );
}
int get(int k, int l, int r, int id)
{
if(l == r) return l;
pushdown(k);
int mid = (l + r) >> 1;
if(cnt[ls(k)] >= id) return get(ls(k), l, mid, id);
else return get(rs(k), mid + 1, r, id - cnt[ls(k)]);
}
int getcnt(int k, int l, int r, int pos)
{
int mid = (l + r) >> 1;
pushdown(k);
if(pos == mid) return cnt[ls(k)];
if(pos < mid) return getcnt(ls(k), l, mid, pos);
if(pos > mid) return cnt[ls(k)] + getcnt(rs(k), mid + 1, r, pos);
}
int main()
{
n = read();
for(int i = 1; i <= n; ++i) b[i] = X[i] = read() - i;
Q = read();
for(int i = 1; i <= Q; ++i)
{
T[i] = read(), G[i] = read();
b[n + i] = G[i] = G[i] - T[i];
}
// for(int i = 1; i <= n; ++i) printf("%d ", X[i]);
// printf("\n");
// for(int i = 1; i <= Q; ++i) printf("%d ", G[i]);
// printf("\n");
// for(int i = 1; i <= n + Q; ++i) printf("%d ", b[i]);
// printf("\n");
sort(b + 1, b + n + Q + 1);
int nn = unique(b + 1, b + n + Q + 1) - (b + 1);
for(int i = 1; i <= n; ++i) x[i] = lower_bound(b + 1, b + nn + 1, X[i]) - b;
for(int i = 1; i <= Q; ++i) g[i] = lower_bound(b + 1, b + nn + 1, G[i]) - b;
for(int i = 1; i <= n; ++i) update1(1, 1, nn, x[i], 1);
// for(int i = 1; i <= n; ++i) printf("%d ", x[i]);
// printf("\n");
// for(int i = 1; i <= Q; ++i) printf("%d ", g[i]);
// printf("\n");
// for(int i = 1; i <= n + Q; ++i) printf("%d ", b[i]);
// printf("\n");
ll ans = 0;
for(int i = 1; i <= Q; ++i)
{
int pos = get(1, 1, nn, T[i]);
if(pos == g[i]) continue;
pair<ll, ll> now = pair<ll, ll>(0ll, 0ll);
// printf("i = %d, T = %d, pos = %d, g = %d\n", i, T[i], pos, g[i]);
if(pos < g[i])
{
int CNT = getcnt(1, 1, nn, pos);
now = query(1, 1, nn, pos + 1, g[i]);
// printf("CNT = %d, sum = %lld, cnt = %lld\n", CNT, now.first , now.second );
now.second += CNT - T[i] + 1, now.first += 1ll * (CNT - T[i] + 1) * b[pos];
update1(1, 1, nn, pos, -(CNT - T[i] + 1));
update2(1, 1, nn, pos + 1, g[i]);
update1(1, 1, nn, g[i], now.second );
}else
{
int CNT = 0;
if(pos > 1) CNT = getcnt(1, 1, nn, pos - 1);
now = query(1, 1, nn, g[i], pos - 1);
// printf("CNT = %d, sum = %lld, cnt = %lld\n", CNT, now.first , now.second );
now.second += T[i] - CNT, now.first += 1ll * (T[i] - CNT) * b[pos];
update1(1, 1, nn, pos, -(T[i] - CNT));
update2(1, 1, nn, g[i], pos - 1);
update1(1, 1, nn, g[i], now.second );
}
// printf("now.first = %lld, second = %lld\n", now.first , now.second );
ans += abs(b[g[i]] * now.second - now.first );
// printf("add = %lld\n", abs(b[g[i]] * now.second - now.first ));
}
printf("%lld\n", ans);
return 0;
}
G - Lexicographically Smallest Permutation
给定序列 和序列 ,一次操作是用 替换 ,问替换任意次后,字典序最小的 序列是什么?
容易发现对于每一个置换环,贪心的确定其在序列 上第一次出现的位置放哪个数即可。
对于第一个置换环,假设经过 次替换使得第一个数最小。
对于第二个置换环,按照每个数从小到大枚举,设需要 次替换使得第一个数是这个环中第 小的数。
设前面的置换环的长度的最小公倍数为 ,那么只需要满足 。
依次判断同余式能否成立即可。
至多每个数都被判断一次,判断一次是 的 。
但是 会很大,需要高精度。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!