【ABC 313】A~E题解
好久没打过比赛了,也好久没写过题解。cf时间有点阴间,来做下ABC
这次做出了A~D,rk900+,E感觉赛时过的和D人数差不多,但我不是很会数数(哭
A
题意:给你 个数 ,找到最小的非负整数 使得
做法: 循环一遍即可。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100 + 10, M = 2e6 + 10, mod = 100003;
int n, a[N];
int main(){
ios::sync_with_stdio(false);
cin >> n;
int x = 0;
for(int i = 1; i <= n; i++) {
cin >> a[i];
if(i > 1) {
x = max(x, a[i] - a[1] + 1);
}
}
cout << x << endl;
return 0;
}
B
题意:有 个人, 对关系,每对关系 表示 能力强于 ,这种关系具有传递性。问谁是最强的,如果不能唯一确定,输出-1
做法:
- 有点复杂,我的做法是floyd,求出每两个人之间的关系
点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100 + 10, M = 2e6 + 10, mod = 100003;
int n, m, a[N];
int g[N][N];
int floyd() {
for(int k = 1; k <= n; k++) {
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(g[i][k] && g[k][j]) {
g[i][j] = 1;
}
}
}
}
// for(int i = 1; i <= n; i++) {
// for(int j = 1; j <= n; j++) {
// if(i == j)continue;
// if(g[i][j] && g[j][i]) return -1;
// }
// }
for(int k = 1; k <= n; k++) {
bool f = 1;
for(int i = 1; i <= n; i++) {
if(g[k][i] || i == k) continue;
else {f = 0; break;}
}
if(f) return k;
}
return -1;
}
int main(){
ios::sync_with_stdio(false);
cin >> n >> m;
for(int i = 1, x, y; i <= m; i++) {
cin >> x >> y;
g[x][y] = 1;
}
cout << floyd() << endl;
return 0;
}
- 把 强于 抽象成 到 有一条有向边,这样可以知道,最强的人就是度数为0的点,假设这样的点只有一个,那么就是答案
点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100 + 10, M = 2e6 + 10, mod = 100003;
int n, m, a[N];
int rd[N];
int main(){
ios::sync_with_stdio(false);
cin >> n >> m;
for(int i = 1, x, y; i <= m; i++) {
cin >> x >> y;
rd[y]++;
}
int cnt = 0, ans;
for(int i = 1; i <= n; i++) {
if(!rd[i]) cnt++, ans = i;
}
if(cnt != 1) ans = -1;
cout << ans << endl;
return 0;
}
C
C - Approximate Equalization 2
题意:给你 个数,定义一次操作为一个数+=1,一个数-=1,问你最少需要多少次操作,能把整个数列变成最大值与最小值的差不超过1
做法:可以求出 ,改变后值为 的有 个,值为 的有 个。将 排序,最后肯定是前 个值为 , 后 个值为 。因为序列增加的值的和与减小的值的和相等,让我们只看应该增大值的 ,如果 小于它应该成为的值,就把 加进答案。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 10;
ll n, m, a[N];
int main(){
ios::sync_with_stdio(false);
cin >> n;
ll tot = 0;
for(int i = 1, x, y; i <= n; i++) {
cin >> a[i];
tot += a[i];
}
sort(a + 1, a + n + 1);
ll ave = tot / n;
ll ans = 0, more = tot - ave * n;
if(more == 0) {
for(int i = 1, x, y; i <= n; i++) {
if(a[i] < ave) ans += ave - a[i];
}
}
else {
// more 个 ave+1, n-more 个 ave
for(int i = 1; i <= n - more; i++) {
if(a[i] < ave) ans += ave - a[i];
else break;
}
for(int i = n - more + 1; i <= n; i++) {
if(a[i] < ave + 1) ans += ave + 1 - a[i];
}
}
cout << ans << endl;
return 0;
}
D
题意:交互题。有 个数,它们的值是0或者1,每次可以询问 个数的和是奇数还是偶数, 最多问 次。求这 个数的值。
做法:
首先问 base = 【1,2,3,...,k-1,k】
然后依次问 tem =【1,2,3,...,k-1,i】 ... (i的值从k+1取到n),共 次。可以知道k+1 到 n 这些数和 的值相同或不同。
之后,问【1,2,3,...,k+1,k】、【1,2,3,...,k+1,k-1,k】...(把k+1插入k-1、k-2、... 1的位置,其他数和base保持一致),共 次,可以知道 1 到 k-1 这些数和 的值相同或不同。
总共就问了 次。
这样就把所有数划分为两个阵营,一个阵营的数值全为0,另一个全为1。
然后根据base的值,它由 个数的和组成,而 为奇数,所以根据这k个数包含奇数个1,偶数个0(和为奇数),或者偶数个1、奇数个0(和为偶数)的关系,就可以知道每个阵营的数的值。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1005 + 10;
int n, k;
int ans[N], result[N];
int base, tem, rec;
set<int> st[2];
inline int ask() {
int res;
cout << '?';
for(int i = 1; i <= k; i++) {
cout << ' ' << ans[i];
}cout << endl;
cin >> res;
return res;
}
void solve() {
for(int i = 1; i <= k; i++) ans[i] = i;
base = ask(); // 1 to k
st[0].insert(k);
for(int i = k + 1; i <= n; i++) {
ans[k] = i;
tem = ask();
if(tem == base) {
st[0].insert(i);
if(i == k + 1) rec = 0;
}
else {
st[1].insert(i);
if(i == k + 1) rec = 1;
}
}
ans[k] = k;
for(int i = k - 1; i >= 1; i--) {
ans[i] = k + 1;
tem = ask();
if(tem == base) st[rec].insert(i);
else st[1 - rec].insert(i);
ans[i] = i;
}
int cnt = 0;
for(int i = 1; i <= k; i++) {
if(st[0].count(i) == 1) cnt++;
}
cnt %= 2;
if(cnt == base) {
//k=1
for(auto x : st[0]) result[x] = 1;
}
else {
//k=0
for(auto x : st[1]) result[x] = 1;
}
cout << '!';
for(int i = 1; i <= n; i++) cout << ' ' << result[i];
cout << endl;
}
int main(){
cin >> n >> k;
solve();
return 0;
}
E
这题是赛后补的
给你一个数字串s(包含1到9),一次操作可以让 变成 个 ,最后一个字符去掉。问多少次操作可以让s变成长度为1,如果不可能,输出-1
做法:容易发现如果出现两个连续的非1数字,答案为-1
我们要求的是操作的次数,记为ans。
如果最后一个数是1,那么
否则,
理解:ans += 1,是删掉当前这个数的操作次数;非1的数x每次操作会增长x-1个1,此前已经操作了ans次,那么一个非1的数y总共增加 (x-1)(ans)次,又因为删掉当前这个数又会导致一次1数量的增长,所以ans+=(x-1)(ans+1)
点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1005 + 10;
int n;
string s;
int main(){
cin >> n >> s;
for(int i = 0; i < s.length(); i++) {
if(i && s[i] != '1' && s[i - 1] != '1') {
cout << -1 << endl;
return 0;
}
}
ll ans = 0;
while(1) {
while(s.length() > 1 && s.back() == '1') s.pop_back(), ans++;
if(s.length() == 1) {cout << ans << endl; return 0;}
int tem = s.back() - '0'; s.pop_back();
ans += 1 + (tem - 1) * (ans + 1) % 998244353;
ans %= 998244353;
}
cout << ans << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?