Codeforces Round 847 (Div. 3)
vp补题
赛时脑子不好使了,两题直接下班
C
题意:
已知一个n
的排列,我们在黑板上每次都按顺序跳过一个数,将这个排列写下来。比如[1, 2, 3, 4]
写下来就是
[2, 3, 4]
[1, 3, 4]
[1, 2, 4]
[1, 2, 4]
,现在给你黑板上写的n
个序列, 求最开始的排列(行和行之间乱序)?
思路:
通过观察不难发现,第一个出现次数最多那个数肯定是排列里的第一个数p1
,然后只要在剩下的序列里找到一个不包含p1
的序列就可以了,
void solve()
{
int n; cin >> n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n - 1; j++)
{
cin >> a[i][j];
}
int b = 0, maxx = 0;
for (int i = 1; i <= n; i++)
{
cnt[a[i][1]]++;
}
for (int i = 1; i <= n; i++)
if (cnt[i] > maxx)
{
b = i;
maxx = cnt[i];
}
for (int i = 1; i <= n; i++)
{
int t = false;
for (int j = 1; j <= n - 1; j++)
{
if (a[i][j] == b) t = true;
}
if (!t)
{
cout << b << ' ';
for (int j = 1; j <= n - 1; j++)
cout << a[i][j] << ' ';
cout << endl;
}
}
memset(cnt, 0, sizeof(cnt));
}
D
题意:
给你一个数组,你可以选一些数组成一个连续上升的序列(s, s + 1, s + 2....)。问你最少可以选多少组
思路:
可以先统计每个数出现的次数,然后从前往后扫一遍如果当前这个数符合条件,就加上它和前面一个数的差
void solve()
{
int n; cin >> n;
map<int, int> mp;
for (int i = 0; i < n; i++)
{
int x; cin >> x;
mp[x]++;
}
int last = -1, ans = 0;
for (auto [x, y] : mp)
{
if (x > last + 1) ans += y; // 不符合条件,重新算
else ans += max(0, y - mp[last]); // 如果小于零说明前面一个出现次数比它多的数已经把它用了,画个柱状图理解一下
last = x;
}
cout << ans << endl;
}
E
题意:
给你一个整数x
, 求两个整数a
和b
,要求a, b
满足x =
思路:
首先要知道一个性质:对于整数a, b如果a + b = A, a
结合上面的性质,不妨假设a =
#include <bits/stdc++.h>
using namespace std;
#define more ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
const int N = 2e5 + 5, MOD = 1e9 + 7, inf = 0x3f3f3f3f;
const long long INF = 1e18;
typedef long long LL;
typedef unsigned long long usLL;
typedef pair<int, int> PII;
void solve()
{
int x; cin >> x;
int a = x / 2;
int b = 2 * x - a;
if ((a ^ b) == x) // 判断一下是不是符合条件
{
cout << a << ' ' << b << endl;
}
else
cout << -1 << endl;
}
int main()
{
more;
int T;
cin >> T;
while (T--)
{
solve();
}
//solve();
return 0;
}
F
题意:
给你一个棵树,让你按照顺序把树上每个节点染成黑色,要求输出每次染色之后黑色节点中距离最近的两个节点的距离(树的价值)
思路:
没啥思路,纯看jiangly代码和题解,可以感性的理解一下
假设当前要染色的节点为x
, 上一次染色的节点位y
和上一次染色后树的价值ans
,那么当前染色完之后的答案应该是min(ans, dis[x])。dis[x]记录的y
节点到y
节点的距离, 证明的话可以把整棵树拉直成一条直线然后然后按照前面的方法依次加点,dis可以用bfs以每次加入的黑点为中心遍历求出(类似维护最短路),关键是更新后的值也必须小于ans(这样可以把复杂度优化到O(n
void solve()
{
int n; cin >> n;
std::vector<int> g(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> g[i];
}
vector<vector<int>> adj(n + 1);
for (int i = 2; i <= n; i++)
{
int a, b; cin >> a >> b;
adj[a].push_back(b);
adj[b].push_back(a);
}
vector<int> dis(n + 1, inf);
int ans = inf;
for (int i = 1; i <= n; i++)
{
ans = min(ans, dis[g[i]]);
if (i > 1) cout << ans << " \n"[i == n];
queue<int> q;
q.push(g[i]);
dis[g[i]] = 0;
while (!q.empty())
{
int x = q.front();
q.pop();
for (auto y : adj[x])
{
if (dis[x] + 1 < dis[y] && dis[x] + 1 < ans)
{
dis[y] = dis[x] + 1;
q.push(y);
}
}
}
}
}
本文作者:自动机
本文链接:https://www.cnblogs.com/monituihuo/articles/17610365.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步