训练情况
赛后反思
div3 给罚时拉满了,C题 \(k-a_i=a_i\) 的情况错掉怒罚五发,D题成结论猜猜乐了,E题看错题了,以为是边一致,实则联通就行,又被并查集背刺了
A题
斐波那契第三位可以从第一二位算出来,也可以从第四五位算出来,两个答案取大值即可
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'using namespace std;void solve(){int a,b,d,e; cin>>a>>b>>d>>e;int ma = 0;int c = a + b;int ans = 0;if(c == a + b) ans++;if(d == b + c) ans++;if(e == c + d) ans++;ma = max(ans,ma);ans = 0;c = e - d;if(c == a + b) ans++;if(d == b + c) ans++;if(e == c + d) ans++;ma = max(ans,ma);cout<<ma<<endl;
}signed main(){int T; cin>>T; while(T--)solve();return 0;
}
B题
我们可以找到 \(0 \sim n-1\) 对应的牛牛,这就是出牌顺序,接下来 \(n \sim nm-1\) 都按这个牛牛顺序出牌,如果有人没有这张牌就是无解情况,否则直接输出最开始的出牌顺序即可
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'using namespace std;void solve(){int n,m; cin>>n>>m;vector<vector<int>> a(n + 1,vector<int>(m + 1));vector<int> pos(n*m*2);for(int i = 1;i<=n;i++){for(int j = 1;j<=m;j++){cin>>a[i][j];pos[a[i][j]] = i;}}vector<int> ans;for(int i = 0;i<n;i++) ans.push_back(pos[i]);bool flag = true;for(int i = n;i<n*m;i++){if(ans[(i-n)%n] != pos[i]) flag = false;}if(flag){for(int i = 0;i<n;i++) cout<<ans[i]<<" ";} else {cout<<-1;}cout<<endl;
}signed main(){int T; cin>>T; while(T--)solve();return 0;
}
C题
这题实则博弈论没有用,就是找数列中 \(a+b=k\) 的对数,因为无论和等不等 \(k\) 的一对,博弈时 Alice 为了让得分最小选择不能和等 \(k\) 的数时,一定还有另一个数给 Bob 选择,所以不会对最终答案造成贡献,这里注意一下 \(k-a_i=a_i\) 的情况,还有数组越界的问题就行
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'using namespace std;void solve(){int n,k; cin>>n>>k;vector<int> a(n + 1);int ma = 0;for(int i = 1;i<=n;i++){cin>>a[i];ma = max(ma,a[i]);}sort(a.begin() + 1,a.end(),greater<int>());vector<int> cnt(ma+1);for(int i = 1;i<=n;i++) cnt[a[i]]++;int ans = 0;for(int i = 1;i<=n;i++){if(k-a[i] >= 1 && k-a[i] <= ma){if(cnt[a[i]]&&cnt[k-a[i]]){ans++;cnt[a[i]]--;cnt[k-a[i]]--;if(cnt[a[i]]<0){ans--;cnt[a[i]]+=2;}}}}cout<<ans<<endl;
}signed main(){int T; cin>>T; while(T--)solve();return 0;
}
D题
结论猜猜乐,因为两个数同减 min 不会改变相对大小关系,想要单调不减,前面的数就得小,盲猜一个全部操作再is_sorted判断单调给我猜对了
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'using namespace std;void solve(){int n; cin>>n;vector<int> a(n + 1);for(int i = 1;i<=n;i++) cin>>a[i];for(int i = 2;i<=n;i++){int mi = min(a[i],a[i-1]);a[i-1]-=mi;a[i]-=mi;}// for(int i = 1;i<=n;i++) cout<<a[i]<<" ";// cout<<endl;if(is_sorted(a.begin() + 1,a.end())) cout<<"YES"<<endl;else cout<<"NO"<<endl;
}signed main(){int T; cin>>T; while(T--)solve();return 0;
}
E题
两个图联通的节点情况要一致,所以我们使用两个并查集分别维护 \(F\) 图和 \(G\) 图的联通块,先维护 \(G\) 图联通,按 \(G\) 图的联通情况去判断 \(F\) 图的联通情况,如果不一致则答案加一,一致则合并 \(G\) 图,然后按 \(F\) 图的联通情况去判断 \(G\) 图的联通情况,如果不一致则答案加一再合并 \(F\) 图。
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'using namespace std;const int N = 2e5 + 3;int fa1[N],fa2[N];int Find1(int x){if(fa1[x] == x) return x;return fa1[x] = Find1(fa1[x]);
}int Find2(int x){if(fa2[x] == x) return x;return fa2[x] = Find2(fa2[x]);
}void Union1(int x,int y){x = Find1(x); y = Find1(y);if(x == y) return;fa1[y] = x;
}void Union2(int x,int y){x = Find2(x); y = Find2(y);if(x == y) return;fa2[y] = x;
}void solve(){int n,m,k; cin>>n>>m>>k;for(int i = 1;i<=n;i++) fa1[i] = i,fa2[i] = i;vector<int> u1(m + 1),v1(m + 1),u2(k + 1),v2(k + 1);for(int i = 1;i<=m;i++){cin>>u1[i]>>v1[i];}for(int i = 1;i<=k;i++){cin>>u2[i]>>v2[i];Union2(u2[i],v2[i]);}int ans = 0;for(int i = 1;i<=m;i++){if(Find2(u1[i]) != Find2(v1[i])){ans++;} else {Union1(u1[i],v1[i]);}}for(int i = 1;i<=k;i++){if(Find1(u2[i]) != Find1(v2[i])){Union1(u2[i],v2[i]);ans++;}}cout<<ans<<endl;
}signed main(){int T; cin>>T; while(T--)solve();return 0;
}