【M Contect-Div.3】#5 题解
本帖由 mengnn 编写,若有疏漏感谢指出。
本帖 2025.10.24 完工。
A. Wind-Money 题解
题面及思路
太简单了,这题没做对的不应该。
按照题面读入 a / b的格式),公式:
最后化简,需要保分子和分母互质:
我们用
注意:十年 OI 一场空,不开____见祖宗。
观察到 int,开 long long 可以解决此问题。
时间复杂度
因为我们要求 gcd,所以最终复杂度
AC Code:
#include<bits/stdc++.h>
using namespace std;
long long a,b,c,d;
char ch;
int main(){
cin>>a>>ch>>b>>c>>ch>>d;
long long x=a*d+b*c;
long long y=b*d;
cout<<(x/__gcd(x,y))<<" / "<<(y/__gcd(x,y));//直接使用 C++ 内置 gcd 函数
return 0;
}
代码来自 mengnn。
B. Wind-Baptism 题解
题面及思路
思路可太好想了,我们可以通过计算来直接求解。
首先,求
接下来,我们再统计次幂和,根据次幂求和公式:
变形得:
所求的原式为:
将公式代入:
其中的 log2(n) 函数来求解
注意:十年 OI 一场空,不开____见祖宗。
观察到 int,开 long long 可以解决此问题。
时间复杂度
由于我们直接取的公式,单次计算复杂度均为
数据组数为
AC Code:
#include<bits/stdc++.h>
using namespace std;
int T;
long long n;
int main(){
cin>>T;
while (T--){
cin>>n;
cout<<(n*(n+1)>>1)-(((1<<((long long)log2(n)+1))-1)<<1)<<'\n';
//代码中我们用 <<1 和 >>1 作为 *2 和 /2
}
return 0;
}
代码来自 mengnn。
C. Wind-Trader 题解
题面及思路
题面写的很丑,zxz 改了之后也很难看。
第一眼看题,很像图论算法,但实则不然。
知道了我们只能将点
首先对于
- 旅行者
a 和b 都认识,那答案加1 ,贡献为0 ; - 旅行者只认识
a ,则对于连接b 的贡献加1 ; - 旅行者只认识
b ,则对于连接a 的贡献加1 ; - 旅行者对于
a 和b 都不认识,则连接a 和b 的共同贡献加1 。
注意:
部分代码:
if (a>b) swap(a,b);
if (f[a]&&f[b]) ++ans1,++ans2;
else if (f[a]) ++t[b];
else if (f[b]) ++t[a];
else if (a==b) ++t[a];
else ++mp[{a,b}];
最后统计答案也分类讨论:
- 连接的是两个有关联的点,直接计算两个单点贡献加上连边贡献:
for (auto i:mp){
int x=i.first.first,y=i.first.second,z=i.second;
ans2=max(ans2,ans1+t[x]+t[y]+z);
}
- 连接的是两个无关的点,直接计算两个单点的贡献(直接取最大值与次大值,贡献最大):
sort(t+1,t+k+1,greater<int>());
ans2=max(ans2,ans1+t[1]+t[2]);
于是你就轻松通过了本题(简单)!
时间复杂度
我们需要进行 map<pair<int,int>,int> 来存储边,且统计时我们还需进行排序,所以单次复杂度
因为我们的算法基底复杂度为
AC Code:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int T,n,m,k,t[N];
bool f[N];
template<typename T>inline void rd(T &x){
x=0;char ch;
bool f=false;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar())
if (ch=='-')
f=true;
for(;ch>='0'&&ch<='9';ch=getchar())
x=(x<<3)+(x<<1)+(ch&15);
if (f) x=-x;
}
template<typename T>inline void wr(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9) wr(x/10);
putchar(x%10+'0');
return ;
}
int main(){
rd(T);
while (T--){
rd(n),rd(m),rd(k);
for (int i=1;i<=k;i++) t[i]=f[i]=0;
for (int i=1,x;i<=n;i++) cin>>x,f[x]=true;
int ans1=0,ans2=0;
map<pair<int,int>,int> mp;
for (int a,b,i=1;i<=m;i++){
rd(a),rd(b);
if (a>b) swap(a,b);
if (f[a]&&f[b]) ++ans1,++ans2;
else if (f[a]) ++t[b];
else if (f[b]) ++t[a];
else if (a==b) ++t[a];
else ++mp[{a,b}];
}
for (auto i:mp){
int x=i.first.first,y=i.first.second,z=i.second;
ans2=max(ans2,ans1+t[x]+t[y]+z);
}
sort(t+1,t+k+1,greater<int>());
ans2=max(ans2,ans1+t[1]+t[2]);
wr(ans2),putchar('\n');
}
return 0;
}
代码来自 mengnn。
D. Wind-Ball 题解
题面及思路
我们设
小球做 check() 函数。
我们在读入之后,将能力进行排序,在排序后的数组中查找能满足条件的最小值,若能查到输出编号;当
若仍不懂见 P8775 青蛙过河。
时间复杂度
二分答案和排序时间复杂度均为
AC Code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 20;
int n,k,a[N],s[N],m;
struct node{
int w,id;
}p[N];
inline bool cmp(node a,node b){
return a.w != b.w ? a.w < b.w : a.id < b.id;
}
inline bool check(int mid){
for ( int i = mid; i <= m; i ++){
if (s[i] - s[i - mid] < 2 * k) return false;
}
return true;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin >> n >> m >> k;
for ( int i = 1; i <= n; i ++){
cin >> p[i].w;
p[i].id = i;
}
for ( int i = 1; i <= m; i ++){
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
int l = 1,r = 1e9,mid;
while (l <= r){
mid = (l + r) >> 1;
if (check(mid)){
r = mid - 1;
}
else l = mid + 1;
}
int ans = r + 1;
sort(p + 1,p + n + 1,cmp);
l = 1,r = n;
while (l <= r){
mid = l + r >> 1;
if (p[mid].w >= ans){
r = mid - 1;
}else l = mid + 1;
}
if (l == n + 1) cout << "Sorry";
else cout << p[r + 1].id;
return 0;
}
代码来自 Realize_Goal。