2024ICPC网络赛第一场题解(部分)
这一场基本纯挂件,给队友翻译翻译题面,帮队友打打板子了,可惜最后40sL题冲了一个
A
题意
给出32个队伍的能力值,和比赛的规则,其中中国队是第一个队伍,问所有分组的情况下,中国队的最好可能成绩是什么。
签到,首先因为32个队能力值都不同,所以只需要看中国队的能力值排名,就决定了最终的答案。具体的话队友应该是手玩了各个情况,写了一堆if else过的。
代码
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define pii pair<int, int>
using namespace std;
bool debug = 1;
#define dbg(x) \
if (debug) \
cerr << BRIGHT_CYAN << #x << COLOR_RESET << " = " << (x) \
<< NORMAL_FAINT << COLOR_RESET << endl;
const string COLOR_RESET = "\033[0m", BRIGHT_CYAN = "\033[1;36m",
NORMAL_FAINT = "\033[0;2m";
void solve() {
int a[32];
int de = 0;
for (int i = 0; i < 32; i++) {
cin >> a[i];
if (a[i] <= a[0])
de++;
}
if (de == 32) {
cout << 1;
} else if (de >= 28) {
cout << 2;
} else if (de >= 14) {
cout << 4;
} else if (de >= 7) {
cout << 8;
} else if (de >= 3) {
cout << 16;
} else
cout << 32;
cout << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
//__builtin_popcountll()
// cout<<fixed<<setprecision(2);
C
题意
给定
首先题目既然只问的奇偶性,就说明不太可能暴力求出来真正的总个数。然后队友画画图,最后猜了个结论,对每个限制
代码
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
bool debug = 1;
#define dbg(x) if(debug) cerr<<BRIGHT_CYAN<<#x<<COLOR_RESET<<" = "<<(x)<<NORMAL_FAINT<<COLOR_RESET<<endl;
const string COLOR_RESET = "\033[0m", BRIGHT_CYAN = "\033[1;36m", NORMAL_FAINT = "\033[0;2m";
void solve(){
int n;
cin >> n;
int sum = 0;
vector<int> a[n + 1]{};
vector<int> vis(n+1);
for (int i = 1; i <= n;i++)
{
int u, v;
cin >> u >> v;
u--;
a[u].pb(v);
a[v].pb(u);
}
function<void(int)> dfs = [&](int u) {
if(vis[u]==0)
sum++, vis[u] = 1;
for(auto p:a[u]){
if(vis[p]==0)
dfs(p);
}
};
dfs(0);
if(sum==n+1)
cout << 1;
else
cout << 0;
cout << '\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t = 1;
cin>>t;
while(t--)
solve();
return 0;
}
//__builtin_popcountll()
// cout<<fixed<<setprecision(2);
F
题意
给一个数组,每次操作选择一个区间,满足区间内的数不能完全相同,然后将区间里的数全都改为区间最大值,问最多能操作多少次
首先容易去考虑,对于每个数,利用单调栈求出它作为区间内唯一最大值的范围,那么操作的时候,就可以从小到大依次操作这些区间,然后基本上就做完了,具体的式子可能还得推推,看代码似乎就是把这样的区间长度加起来。
代码
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
bool debug = 1;
#define dbg(x) if(debug) cerr<<BRIGHT_CYAN<<#x<<COLOR_RESET<<" = "<<(x)<<NORMAL_FAINT<<COLOR_RESET<<endl;
const string COLOR_RESET = "\033[0m", BRIGHT_CYAN = "\033[1;36m", NORMAL_FAINT = "\033[0;2m";
const int N = 2e5 + 999;
int n, a[N], stk[N], top, l[N], r[N];
void solve(){
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
stk[top = 0] = 0;
for (int i = 1; i <= n; i++){
while(top && a[i] > a[stk[top]])
top--;
l[i] = stk[top] + 1;
stk[++top] = i;
}
stk[top = 0] = n + 1;
a[n + 1] = 0;
for (int i = n; i >= 1; i--){
while(top && a[i] > a[stk[top]])
top--;
r[i] = stk[top] - 1;
if(a[r[i] + 1] == a[i])
r[i] = i;
stk[++top] = i;
}
int ans = 0;
for (int i = 1; i <= n; i++)
ans += r[i] - l[i];
cout << ans << '\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t = 1;
cin>>t;
while(t--)
solve();
return 0;
}
//__builtin_popcountll()
// cout<<fixed<<setprecision(2);
G
题意
给一个长度
首先看到中位数很容易去考虑二分答案后,转01矩阵。那么这题同理,首先因为
代码
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
bool debug = 1;
#define dbg(x) if(debug) cerr<<BRIGHT_CYAN<<#x<<COLOR_RESET<<" = "<<(x)<<NORMAL_FAINT<<COLOR_RESET<<endl;
const string COLOR_RESET = "\033[0m", BRIGHT_CYAN = "\033[1;36m", NORMAL_FAINT = "\033[0;2m";
const int N = 2033;
int n, a[N], rk[N], s[N], b[N][N], c[N][N], sb[N][N];
bool check(int x){
for (int i = 1; i <= n; i++){
s[i] = s[i - 1] + (a[i] > x);
}
int cnt = 0;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
b[i][j] = !(j - i + 1 - s[j] + s[i - 1] >= (j - i + 2) / 2);
/*for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
cout << b[i][j] << " \n"[j == n];*/
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
sb[i][j] = sb[i - 1][j] + sb[i][j - 1] + b[i][j] - sb[i - 1][j - 1];
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++){
c[i][j] = (sb[j][j] - sb[i - 1][j] - sb[j][i - 1] + sb[i - 1][i - 1]);
int sz = (j - i + 2) * (j - i + 1) / 2;
if(sz - c[i][j] >= (sz + 1) / 2)
cnt++;
}
return cnt >= (n * (n + 1) / 2 + 1) / 2;
}
void solve(){
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i], rk[i] = a[i];
sort(rk + 1, rk + n + 1);
int l = 1, r = n, mid;
while(l < r){
mid = (l + r) >> 1;
if(check(rk[mid]))
r = mid;
else
l = mid + 1;
}
cout << rk[l];
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t = 1;
while(t--)
solve();
return 0;
}
//__builtin_popcountll()
// cout<<fixed<<setprecision(2);
H
题意
括号序列长度为
括号序列会想起来很久之前牛客的一次练习赛(https://ac.nowcoder.com/acm/contest/75768/F)里面有跟网络流结合起来判合法括号,看到数据范围挺小,就让队友想想能不能用网络流,最大流保证括号合法,费用流求最大价值。然后队友比划比划后想出来建模了,把左括号数量下界的限制,转化为右括号的数量上界限制,先把所有价值加起来,然后匹配上一个右括号,相当于去掉所在位置的价值,所以最小费用就可以让最后剩的价值最大。具体建模可以看看代码里面,而且有一个wa点,就是如果给的左括号数量本身不合法,可能建模会建出来负的边权,需要特判掉-1.
代码
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
bool debug = 1;
#define dbg(x) if(debug) cerr<<BRIGHT_CYAN<<#x<<COLOR_RESET<<" = "<<(x)<<NORMAL_FAINT<<COLOR_RESET<<endl;
const string COLOR_RESET = "\033[0m", BRIGHT_CYAN = "\033[1;36m", NORMAL_FAINT = "\033[0;2m";
const int N = 1009;
int n, m, dist[N], head[N], flow[N], vis[N], S, T, tot, pre[N];
struct Edge{
int v, rest, p, nxt;
} edge[N * 40];
typedef long long ll;
int col[N], cnt[N], val[N];
bool SPFA() {
for (int i = 1; i <= n + m + 10; i++)
dist[i] = flow[i] = 1e16, vis[i] = 0;
queue<int> q;
q.push(S), dist[S] = 0;
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = 0;
for (int i = head[u]; i; i = edge[i].nxt) {
if (edge[i].rest && dist[edge[i].v] > dist[u] + edge[i].p) {
dist[edge[i].v] = dist[u] + edge[i].p;
pre[edge[i].v] = i;
flow[edge[i].v] = min(flow[u], edge[i].rest);
if (!vis[edge[i].v])
q.push(edge[i].v), vis[edge[i].v] = 1;
}
}
}
return dist[T] < 1e15;
}
void maxflow() {
ll ans = 0, f = 0;
//cout << "maxflow" << endl;
while (SPFA()) {
//cout << "SPFA" << endl;
//cout << flow[T] << " " << dist[T] << endl;
f += flow[T];
ans += flow[T] * dist[T];
int x = T;
while (x != S) {
int y = pre[x];
edge[y].rest -= flow[T];
edge[y ^ 1].rest += flow[T];
x = edge[y ^ 1].v;
}
}
if(f < n / 2)
cout << "-1\n";
else {
ans = -ans;
for (int i = 1; i <= n; i++)
ans += val[i];
cout << ans << '\n';
}
}
void add(int u, int v, int c, int w, int t = 1){
edge[++tot] = (Edge){v, c, w, head[u]};
head[u] = tot;
if(t)
add(v, u, 0, -w, 0);
}
void solve(){
cin >> n >> m;
for(int i = 1; i <= m; i++)
cin >> cnt[i], cnt[i] = -cnt[i];
n *= 2;
for (int i = 1; i <= n; i++){
cin >> col[i];
cnt[col[i]]++;
}
for (int i = 1; i <= n; i++)
cin >> val[i];
//cout << "finish" << endl;
memset(head, 0, sizeof head);
S = 1, T = 2;
tot = 1;
add(S, n + 2, n / 2, 0);
for (int i = n; i > 1; i--)
add(i + 2, i + 1, (i - 1) / 2, 0), add(i + 2, n + 2 + col[i], 1, val[i]);
add(1 + 2, n + 2 + col[1], 1, val[1]);
bool flag = 1;
for (int i = 1; i <= m; i++){
add(n + 2 + i, T, cnt[i], 0);
if(cnt[i] < 0)
flag = 0;
}
if(flag) maxflow();
else
cout << "-1\n";
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t = 1;
cin>>t;
while(t--)
solve();
return 0;
}
//__builtin_popcountll()
// cout<<fixed<<setprecision(2);
M
题意
给出每个提交,包含队伍名、题号、通过情况,问哪个题通过的队伍数最多
整场就这个题是我写的/(ㄒoㄒ)/~~,直接用STL暴力对每个题号的通过队伍名字放set去重,然后遍历map已经是按字典序从小到大,然后判断一下就行。
代码
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
bool debug = 1;
#define dbg(x) if(debug) cerr<<BRIGHT_CYAN<<#x<<COLOR_RESET<<" = "<<(x)<<NORMAL_FAINT<<COLOR_RESET<<endl;
const string COLOR_RESET = "\033[0m", BRIGHT_CYAN = "\033[1;36m", NORMAL_FAINT = "\033[0;2m";
void solve(){
int n; cin >> n;
//teamA A accepted
map<string, set<string>> mp;
for (int i = 1; i <= n; i++) {
string a, b, c;
cin >> a >> b >> c;
if (c[0] == 'a') {
mp[b].insert(a);
}
}
int mx = 0;
string ans;
for (auto it : mp) {
if (it.second.size() > mx) {
mx = it.second.size();
ans = it.first;
}
}
cout << ans << "\n";
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t = 1;
cin>>t;
while(t--)
solve();
return 0;
}
//__builtin_popcountll()
// cout<<fixed<<setprecision(2);
L (参考思路)
题意
有
首先注意到,一个按钮如果能使用,要么移动的到的
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!