2024CCPC郑州邀请赛
2024CCPC郑州邀请赛题解
[比赛地址](2024 National Invitational of CCPC (Zhengzhou), 2024 CCPC Henan Provincial Collegiate Programming Contest)
A:
解题思路:
设
我们构造一个数
如果
如果
新小技巧,快速求整型数据十进制数位:
int len = to_string(n).size();
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll inf = 1ll << 60;
void solve()
{
ll n, d;
scanf("%lld %lld", &n, &d);
int len = to_string(n).size();
ll N = 1ll * 123456789 * 10 + d;
for (int i = 1; i <= len; i++)
{
N *= 10;
}
ll ans = (N + n - 1) / n;
printf("%lld\n", ans);
}
int main()
{
int t = 1;
scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
B:
解题思路:
考虑对于当前位置
如果前面位置能够花费比
所以,单调栈优化
如果前面没有这种位置,说明存钱到位置
全过程取最大值。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void solve()
{
int n;
cin >> n;
vector<ll> a(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
vector<ll> f(n + 1), b(n + 1);
ll ans = 0;
stack<int> stk;
for (int i = 1; i <= n; i++)
{
while (stk.size() && a[stk.top()] > a[i])
{
stk.pop();
}
if (stk.empty())
{
f[i] = i / a[i];
b[i] = i % a[i];
}
else
{
int idx = stk.top();
f[i] = f[idx] + (i - idx + b[idx]) / a[i];
b[i] = (i - idx + b[idx]) % a[i];
}
stk.push(i);
ans = max(ans, f[i]);
// cout << i << ' ' << b[i] << ' ' << f[i] << endl;
}
printf("%lld\n", ans);
}
int main()
{
int t = 1;
// scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
C:
解题思路:
观察发现,根据题目要求,对于一个数字最开始出现位置到最后出现位置之间的所有数字,变换后都应当相等。否则不可能非递减。
题目案例:
10
1 10 2 6 10 8 9 4 4 5
我们按照上述说法举例分段:
[1], [10, 2, 6, 10], [8], [9], [4, 4], [5]
题目案例变换后:
[1], [2, 2, 2, 2], [2], [2], [4, 4], [5]
通过逻辑发现,如果出现相交,那么直接扩大:
10
1, 10, 9, 8, 6, 10, 7, 6, 4, 5
分段:
[1], [10, 9, 8, 6, 10, 7, 6], [4], [5]
映射函数
题目要求修改最少得映射函数的值,使得原序列映射后非递减。
即,找到原序列中最长上升子序列(
我们发现,对于一个元素段,我们最多可以保留一个元素不变,即所有元素都变成那个保留的元素。
所以,我们对每个元素段进行内部降序排序,使得
如何快速处理出元素段区间?
使用差分,每个元素可看作是一个区间
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define fi first
#define se second
void solve()
{
int n;
scanf("%d", &n);
vector<int> a(n + 1);
vector<int> l(n + 1, n + 1), r(n + 1, -1);
vector<bool> vis(n + 1);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
l[a[i]] = min(l[a[i]], i);
r[a[i]] = i;
vis[a[i]] = true;
}
vector<int> d(n + 1);
for (int i = 1; i <= n; i++)
{
if (l[i] <= r[i])
{
d[l[i]]++;
d[r[i]]--;
}
}
// d[i] = 0µÄλÖ㬾ÍÊÇÒ»¸ö¶ÎµÄĩβ
for (int i = 1; i <= n; i++)
{
d[i] += d[i - 1];
// cout << d[i] << " \n"[i == n];
}
int lst = 1;
for (int i = 1; i <= n; i++)
{
if (d[i] == 0)
{
// cout << lst << ' ' << i << endl;
sort(a.begin() + lst, a.begin() + i + 1, greater<int>());
lst = i + 1;
}
// cout << i << " " << lst << endl;
}
// for (int i = 1; i <= n; i++)
// {
// cout << a[i] << " \n"[i == n];
// }
vector<int> q(n + 1, 0);
int len = 0;
for (int i = 1; i <= n; i++)
{
int lp = 0;
int rp = len + 1;
while (lp + 1 < rp)
{
int mid = lp + rp >> 1;
if (q[mid] >= a[i])
{
rp = mid;
}
else
{
lp = mid;
}
}
len = max(len, lp + 1);
q[lp + 1] = a[i];
// cout << i << ' ' << len << endl;
}
int cnt = 0;
for (int i = 1; i <= n; i++)
{
if (vis[i] == true)
{
cnt++;
}
}
int ans = cnt - len;
printf("%d\n", ans);
}
int main()
{
int t = 1;
// scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
D:
解题思路:
可知,当
考虑给定不重合的点集中找到两个点,使得该两点相连后的线段,斜率最接近
我们这里将
同理,
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define fi first
#define se second
void solve()
{
ll n;
scanf("%d", &n);
vector<pair<ll, ll>> v(n + 1);
for (int i = 1; i <= n; i++)
{
scanf("%lld %lld", &v[i].fi, &v[i].se);
}
sort(v.begin() + 1, v.end(), [&](pair<ll, ll> a, pair<ll, ll> b){
return a.fi + a.se < b.fi + b.se;
});
double ans = 0;
for (int i = 1; i < n; i++)
{
ll dx = abs(v[i].fi - v[i + 1].fi);
ll dy = abs(v[i].se - v[i + 1].se);
ans = max(ans, 1.0 * (dx + dy) / (sqrt(dx * dx + dy * dy)));
}
sort(v.begin() + 1, v.end(), [&](pair<ll, ll> a, pair<ll, ll> b){
return a.fi - a.se < b.fi - b.se;
});
for (int i = 1; i < n; i++)
{
ll dx = abs(v[i].fi - v[i + 1].fi);
ll dy = abs(v[i].se - v[i + 1].se);
ans = max(ans, 1.0 * (dx + dy) / (sqrt(1.0 * dx * dx + dy * dy)));
}
printf("%.12lf\n", ans);
}
int main()
{
int t = 1;
scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
F:
解题思路:
签到,按题意模拟。
代码:
#include<bits/stdc++.h>
using namespace std;
void solve()
{
int n;
cin >> n;
int ans = 0;
for (int i = 1; i <= n; i++)
{
string s;
cin >> s;
if (s.size() == 5 && s[2] == s[4])
{
set<char> se;
for (int i = 0; i < 4; i++)
{
se.insert(s[i]);
}
if (se.size() == 4)
{
ans++;
}
}
}
cout << ans << endl;
}
int main()
{
int t = 1;
while (t--)
{
solve();
}
return 0;
}
H:
解题思路:
观察发现,最后得到的序列一定是唯一的。
我们可以先将所有数进行排序,得到最终序列。
然后对着最终序列,按照顺序模拟操作:
如果当前没有最小数可以取,那么直接结束,概率为
暴力模拟即可。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define fi first
#define se second
const int mod = 998244353;
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 solve()
{
int n;
scanf("%d", &n);
vector<int> a(2 * n + 1);
vector<int> v;
for (int i = 1; i <= 2 * n; i++)
{
scanf("%d", &a[i]);
if (a[i] != -1)
{
v.push_back(a[i]);
}
}
sort(v.begin(), v.end());
map<int, int> cnt;
int cur = 0;
bool vis = false;
ll ans = 1;
int len = 0;
for (int i = 1; i <= 2 * n; i++)
{
if (a[i] == -1)
{
int x = v[cur];
if (cnt[x] > 0)
{
ans = ans * (cnt[x] * qmi(len, mod - 2) % mod) % mod;
cnt[x]--;
cur++;
len--;
}
else
{
vis = true;
break;
}
continue;
}
cnt[a[i]]++;
len++;
}
if (vis)
{
ans = 0;
}
printf("%lld\n", ans);
}
int main()
{
int t = 1;
// scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
J:
解题思路:
出现偶数,使偶数出现在个位。
否则输出
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void solve()
{
string s;
cin >> s;
int cnt = 0;
for (int i = 0; i < 5; i++)
{
int x = s[i] - '0';
if (x & 1)
{
cnt++;
}
}
if (cnt == 5)
{
printf("97531\n");
}
else
{
int x = s[4] - '0';
if (x & 1)
{
for (int i = 0; i < 4; i++)
{
int c = s[i] - '0';
if (c % 2 == 0)
{
swap(s[i], s[4]);
break;
}
}
}
cout << s << "\n";
}
}
int main()
{
int t = 1;
scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
K:
解题思路:
题目明示换根
美丽节点的判断:对于当前节点来说,如果所有子节点的
如何换根:
假设
那么,首先
然后,我们考虑
深搜完记得变回去。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define fi first
#define se second
void solve()
{
int n;
scanf("%d", &n);
vector<int> a(n + 1, -1), f(n + 1, 0);
int ans = 0;
vector<vector<int>> e(n + 1, vector<int>());
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
for (int i = 1; i < n; i++)
{
int a, b;
scanf("%d %d", &a, &b);
e[a].push_back(b);
e[b].push_back(a);
}
auto dfs =[&](auto self, int u, int fa) -> void
{
for (auto v : e[u])
{
if (v == fa)
{
continue;
}
self(self, v, u);
f[u] += f[v];
if (2 * a[v] < a[u])
{
f[u]++;
}
}
};
dfs(dfs, 1, 0);
auto efs =[&] (auto self, int u, int fa) -> void
{
bool vis = false;
for (auto v : e[u])
{
if (v == fa)
{
continue;
}
f[u] -= f[v] + (2 * a[v] < a[u]);
f[v] += f[u] + ((2 * a[u] < a[v]));
self(self, v, u);
f[v] -= f[u] + ((2 * a[u] < a[v]));
f[u] += f[v] + (2 * a[v] < a[u]);
}
for (auto v : e[u])
{
if (f[v] != 0 || 2 * a[v] < a[u])
{
vis = true;
}
}
if (!vis)
{
ans++;
}
};
efs(efs, 1, 0);
printf("%d\n", ans);
}
int main()
{
int t = 1;
scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
L:
解题思路:
观察发现,我们将60个
所以,我们最多
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll inf = 1ll << 60;
void solve()
{
int n, m;
scanf("%d %d", &n, &m);
vector<int> a(m + 1);
for (int i = 1; i <= m; i++)
{
scanf("%d", &a[i]);
}
vector<ll> f(m + 1, inf);
f[0] = 0;
ll ans = inf;
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= 60; j++)
{
if (i - j < 0)
{
break;
}
f[i] = min(f[i], f[i - j] + a[i] + (ll)pow(j, 4));
}
}
printf("%lld\n", f[m]);
}
int main()
{
int t = 1;
// scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
M:
解题思路:
发现对于位置
二分。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void solve()
{
int n;
scanf("%d", &n);
vector<ll> a(n + 1), b(n + 1);
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
}
for (int i = 1; i <= n; i++)
{
scanf("%lld", &b[i]);
}
ll l = -1;
ll r = 1e9 + 1;
auto check = [&](ll mid)
{
ll tl = 0;
ll tr = 0;
for (int i = 1; i <= n; i++)
{
if (i == 1)
{
tl = a[i] - b[i] * mid;
tr = a[i] + b[i] * mid;
}
else
{
tl = max(tl, a[i] - b[i] * mid);
tr = min(tr, a[i] + b[i] * mid);
}
if (tl > tr)
{
return false;
}
}
return true;
};
while (l + 1 < r)
{
ll mid = l + r >> 1;
if (check(mid))
{
r = mid;
}
else
{
l = mid;
}
}
cout << r << '\n';
}
int main()
{
int t = 1;
scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧