【牛客训练记录】西南财经大学2025第二届“奇点杯”程序设计竞赛(同步赛)
训练情况
赛后反思
题目简短但是遇到典题但是不会做,感觉edu的场都打不动,遇到adhoc题就拉闸了
A题
这题我们观察到 \(n\) 很大,我们考虑去枚举完全平方数,这样复杂度是 \(O(\sqrt{n})\) 的,完全平方数要枚举到 \(2n - 1\) 因为是 \(i < j \le n\),所以 \(i\) 最大是 \(n-1\),\(j\) 最大是 \(n\),之后我们对于枚举出的完全平方数考虑有多少对 \((i,j)\) 使得 \(i+j=x\),显然我们考虑较小的那个 \(i\) 的取值范围即可,取值下界是 \(j\) 卡到最大 \(n\) 的时候,\(i\) 最小,所以最小的 \(i\) 是 \(x-i\),取值上界是 \(\lfloor \frac{x-1}{2} \rfloor\),因为我们不能让 \(j \le i\),所以只能两个值贡献均摊掉,所以是除二,减一的目的是 \(i = j\) 的情况不合法,所以我们对 \(i\) 值域求和就是答案
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
void solve(){
int n; cin>>n;
int ans = 0;
for(int i = 2;i*i<=2*n-1;i++){
int mi = max(1ll,i*i-n);
int ma = min(n,(i*i-1)/2);
ans += ma-mi+1;
// cout<<i*i<<" "<<mi<<" "<<ma<<endl;
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
// int T; cin>>T; while(T--)
solve();
return 0;
}
B题
求所有连续子数组的和,我们考虑拆贡献,考虑每一位对最后答案的贡献,我们试着枚举一下连续子数组,我们发现对于某一位对于答案的贡献可以为左边任意一个数为连续子数组的左边界,自身为右边界,或者自身为左边界,右边的任意一个数为右边界,还有一种左边界左边的数跨过自身到右边界右边的数,所以我们对每一位数对这三种贡献的情况求和就是答案
点击查看代码
#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];
if(n == 1){
cout<<a[1]<<endl;
return;
}
int ans = 0;
for(int i = 2;i<n;i++){
ans += (i-1)*a[i];
ans += (n-i+1)*a[i];
ans += (i-1)*(n-i)*a[i];
}
ans += a[1]*n;
ans += a[n]*n;
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
// int T; cin>>T; while(T--)
solve();
return 0;
}
K题
并查集模板题,求联通问题直接图论建边使用并查集维护,对于 \(k\) 个互不相同的数求根节点,判断是否同属一个根节点即可,代码实现使用了 set 统计不同的个数
点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
const int N = 1e5 + 3;
int fa[N];
int Find(int x){
if(fa[x] == x) return x;
return fa[x] = Find(fa[x]);
}
void Union(int x,int y){
x = Find(x); y = Find(y);
if(x == y) return;
fa[y] = x;
}
void solve(){
int n,m; cin>>n>>m;
for(int i = 1;i<=n;i++) fa[i] = i;
for(int i = 1;i<=m;i++){
int x,y; cin>>x>>y;
Union(x,y);
}
int k; cin>>k;
set<int> s;
while(k--){
int x; cin>>x;
s.insert(Find(x));
}
if(s.size() > 1) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T; cin>>T; while(T--)
solve();
return 0;
}