A - Shuffled Equation
思路:直接将其排序,如果最小的两个相乘等于最大的,那么就是Yes,否则就是No
#include <bits/stdc++.h>
using namespace std;
#define int long long
int a[3];
signed main()
{ cin>>a[0]>>a[1]>>a[2];sort(a,a+3);if(a[0]*a[1]==a[2]){cout<<"Yes";}else{cout<<"No";}return 0;
}
B - Who is Missing?
思路:用一个vis标记数组,如果出现在a数组的就标记为1,然后从1~n遍历,哪个位置上的vis是0,就是没有出现过的,输出就行,那怎样去统计个数呢?这个也简单,如果原本是vis是0,但是变成了1,就cnt++,最后直接输出n-cnt即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
int a[200005];
int vis[200005];
signed main()
{ cin>>n>>m;int cnt=0;for(int i=1;i<=m;i++){cin>>a[i];if(vis[a[i]]==0){cnt++;vis[a[i]]=1;}}cout<<n-cnt<<"\n";for(int i=1;i<=n;i++){if(vis[i]==0){cout<<i<<" ";}}return 0;
}
C - Bib
思路:这题其实更偏向于一种逻辑题吧,反正不难写,我们读清楚题目的意思就是,按照围裙号大小的顺序,输出穿着当前围裙的人盯着的人身上的围裙号
我们完全可以将题目拆分成这四句话,因此我们可以用一个pair来存储围裙号和人的编号,然后排序一下,就可以完成前两句话,盯着的人,我们可以用一个b数组去存储,因此第三局话也完成了,然后用a数组去存储每个人身上的围裙号,因此,第四句话也完成了,题目就解决了
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n;
int a[300005];
int b[300005];
int c[300005];
pair<int,int> p[300005];
signed main()
{ cin>>n;for(int i=1;i<=n;i++){cin>>b[i];}for(int i=1;i<=n;i++){cin>>a[i];p[i].first=a[i];p[i].second=i;}sort(p+1,p+1+n);for(int i=1;i<=n;i++){cout<<a[b[p[i].second]]<<" ";}return 0;
}
D - Doubles
思LLLLLLL: 我们看到数据很小,因此最大可以用到n^3的做法,我们不妨去这么解决,我们采取定1变1的做法,先去将定的筛子的面用map去统计一下,每个数字出现的次数,然后去遍历变的筛子的面,用ans去累加,最后除以k[i]和k[j],两个筛子的面的累乘即可,然后不断去更新最大值,就能解决了
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
int n;
int cnt[105];
vector<int> a[105];
signed main()
{cin>>n;for(int i=1;i<=n;i++){cin>>cnt[i];a[i].resize(cnt[i]+1);for(int j=1;j<=cnt[i];j++){cin>>a[i][j];}}double maxn=0.0;for(int i=1;i<=n;i++){unordered_map<int,int> mp;for(int j=1;j<=cnt[i];j++){mp[a[i][j]]++;}double p=0.0;for(int j=i+1;j<=n;j++){int ans=0;for(int k=1;k<=cnt[j];k++){ans+=mp[a[j][k]];}p=static_cast<double>(ans)/cnt[j];p/=cnt[i];maxn=max(maxn,p);}}cout << fixed << setprecision(10) << maxn;return 0;
}
E - Cables and Servers
思路:
Q1:这题是要让所有电脑连通在一起的最小操作序列,我们能否将问题拆分开来
A1:可以将问题分解为 如何将一整个图变成连通图 和 怎样才能有最小的操作序列
Q2:如何将一整个图变成连通图
A2:题目中已经说了,改变一条边的端点,从而使整张图连通,我们想到了并查集
Q3:我们要去改变哪些边的端点呢?
A3:如果说,某两个点,在去掉这条边后,仍然在一张连通图中(即成环的边),就说明这条边可以用,改变后不影响结果
Q4:我们这样是否是有最小的操作序列呢
A4:我们每次只对两个没有连通的分量,链接只一次,一定是最小的操作序列
因此问题得到解决开始敲代码
我们现将形成环的边存进一个数组里面,然后将每个连通分量的根结点抽出来,改变上述成环的边的端点去链接独立的连通分量,但是要注意,假如端点的跟节点,等于当前抽出来的根结点,要将抽出来的根节点,与独立连通分量数组的末尾换一下,直到只剩下一条连通分量即可解决问题
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
int m;
int u,v;
pair<int,int> edge[200005];
int f[200005];
vector<int> vec;//重环的边
vector<int> s;//每个连通图的代表
int cha(int x)
{if(x==f[x])return x;return f[x]=cha(f[x]);
}
signed main()
{cin>>n>>m;for(int i=1;i<=n;i++){f[i]=i;}for(int i=1;i<=m;i++){cin>>u>>v;edge[i].first=u;edge[i].second=v;int fu=cha(u);int fv=cha(v);if(fu!=fv){f[fu]=fv;}else{vec.push_back(i);}}for(int i=1;i<=n;i++){if(f[i]==i){s.push_back(i);}}cout<<s.size()-1<<"\n";while(s.size()>1){int k=vec.back();//重边的编号 vec.pop_back();int t=s.back();//连通图的代表 s.pop_back();pair<int,int> p=edge[k];u=p.first;v=p.second;int fu=cha(u);int fv=cha(v);if(fv==t){swap(t,s.back());}f[t]=fu;cout<<k<<" "<<v<<" "<<t<<"\n";}return 0;
}