AtCoder Beginner Contest 392(ABCDE)

A - Shuffled Equation

翻译:

        你被给予了一个序列A=(A_{1},A_{2},A_{3})

        让B=(B_{1},B_{2},B_{3})为A的任意排列。

        确定是否可能使B_{1}\times B_{2}=B_{3}

思路:

        让较小的两个相乘,判断是否与最大的相同。

实现:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

int main(){
    // 关闭输入输出流同步
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // 不使用科学计数法
    // cout<<fixed;
    // 中间填保留几位小数,不填默认
    // cout.precision();
    vector<int> a(3);
    for (int& i:a)cin>>i;
    sort(a.begin(),a.end());
    if (a[0]*a[1]==a[2]){
      cout<<"Yes"<<endl;
    }else{
      cout<<"No"<<endl;
    }
}


B - Who is Missing?

 翻译:

        你被给予了一个长为M的整数序列A=(A_{1},A_{2},...,A_{M})

        A中的每个元素介于1与N之间,包括1,N,并且每个元素都不同。

        列出所有没出现在A中的1到N按升序排列。

思路:

        设置一个访问数组vis,初始化为1。遍历A出现在元素 i 将vis[i]=0。最后遍历vis中为1的值。

实现:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;


int main(){
    // 关闭输入输出流同步
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // 不使用科学计数法
    // cout<<fixed;
    // 中间填保留几位小数,不填默认
    // cout.precision();
    int n,m;
    cin>>n>>m;
    vector<int> a(n+1,1);
    for (int i=1,num;i<=m;i++){
      cin>>num;
      a[num] = 0;
    }
    int f = 0;
    cout<<n-m<<endl;
    for (int i=1;i<=n;i++){
      if (f) cout<<" ";
      if (a[i]){
        cout<<i;
        f = 1;
      }
    }
}


C - Bib

 翻译:

        有 N 个人从 1 到 N 开始标记。

        i 号人穿着数字为 Q_{i} 的围裙并且盯着 P_{i} 号人。

        对于每个i=1,2,...,N,找到穿着围裙 i 的人盯着的人上围裙的数字。

思路:

        创建3个数组,围裙 i 所对应的人,i 号人所盯的人,i 号人所穿的围裙。

实现:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;


int main(){
    // 关闭输入输出流同步
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // 不使用科学计数法
    // cout<<fixed;
    // 中间填保留几位小数,不填默认
    // cout.precision();
    int n;
    cin>>n;
    // 围裙 穿的人
    vector<int> a(n+1);
    // 穿的人 围裙
    vector<int> c(n+1);
    // 当前的人 看的人
    vector<int> b(n+1);
    for (int num,i=1;i<=n;i++){
      cin>>num;
      b[i] = num;
    }
    for (int num,i=1;i<=n;i++){
      cin>>num;
      a[num] = i;
      c[i] = num;
    }
    for (int i=1;i<=n;i++){
      if (i!=1) cout<<" ";
      cout<<c[b[a[i]]];
    }
}

D - Doubles

  翻译:

        这有 N 个筛子。第 i 个筛子有 K_{i} 个面,数字A_{i_{1}},A_{i_{2}},...,A_{i_{K_{i}}}被写在他们上。当你旋转这个筛子每个面出现的可能性为 \frac{1}{K_{i}}

        你从 N 个筛子中选择两个筛子并旋转他们。确定两个筛子出现相同数字的最大可能性,当筛子选择最佳时。

思路:

    使用map<int,int>记录每个筛子中各个数字出现的次数。

    最后对每个筛子进行两两配对。

实现:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;


int main(){
    // 关闭输入输出流同步
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // 不使用科学计数法
    // cout<<fixed;
    // 中间填保留几位小数,不填默认
    cout.precision(15);
    int n;
    cin>>n;
    vector<int> k(n);
    // 记录每个筛子中的各种数字数量
    vector<unordered_map<int,int>> cnts(n);
    // 最大可能性
    double ans = 0;
    for (int num,i=0;i<n;i++){
      cin>>k[i];
      for (int j=0;j<k[i];j++){
        cin>>num;
        cnts[i][num]++;
      }
    }
    // 筛子两两配对
    for (int i=0;i<n;i++){
      for (int j=i+1;j<n;j++){
        int ki = k[i],kj = k[j];
        double cnt = 0;
        // 遍历筛子i的每种数字及其数量
        for (auto &[x,y]:cnts[i]){
          // 筛子j存在数字 x 
          if (cnts[j].count(x))
          cnt += 1.0*y/ki*1.0*cnts[j][x]/kj;
        }
        ans = max(ans,cnt);
      }
    }
    cout<<ans<<endl;
}

E - Cables and Servers

  翻译:

        这有N个数字1到N的服务器和M条数字1到M的电缆。

        电缆i双向连接服务器A_{i},B_{i}

        执行下列操作一些次数(可能0次),使所有服务器通过电缆相互连接。

  •         操作:选择一条电缆并重新连接其尾部到另一个服务器。

        找到最小数量的操作数并输出到这个最小操作数的操作序列。

思路:

        先找到每个连通块的无用边,而每条无用边都可连接两个连通块,对无用边进行遍历使连通块和为1即可。(并查集)

实现:

#include<bits/stdc++.h>
using namespace std;
const int MX = 2e5+10;
int n,m;
// 并查集,无用边
vector<int> f(MX),sizes(MX),unvail;
// 边
vector<vector<int>> edge(MX,vector<int>(2));
// 找祖宗
int find(int x){
  return f[x]==x ? x : f[x] = find(f[x]);
}
// 合并
void merge(int x,int y){
  x = find(f[x]);
  y = find(f[y]);
  if (x==y) return;
  if (sizes[x]<sizes[y]) swap(x,y);
  f[y] = x;
  sizes[x]+=sizes[y];
}
int main(){
  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
  cin>>n>>m;
  for (int i=0;i<=n;i++){
    f[i] = i;
    sizes[i] = 1;
  }
  for (int i=1;i<=m;i++){
    cin>>edge[i][0]>>edge[i][1];
    int x = find(edge[i][0]),
        y = find(edge[i][1]);
    // 不在同一连通块
    if (x!=y){
      merge(x,y);
      // 在同一连通块,为无用边
    }else{
      unvail.push_back(i);
    }
  }
  // 记录连通块
  unordered_set<int> dsus;
  for (int i=1;i<=n;i++){
    if (f[i]==i) dsus.insert(i);
  }

  vector<array<int,3>> ans;
  // 连接dsus次连通块
  for (int i:unvail){
    int x = edge[i][0],
        y = edge[i][1];
    x = find(f[x]);
    int now_dus=-1;
    while (!dsus.empty()){
      int tmp = *dsus.begin();
      dsus.erase(dsus.begin());
      // 属于自身的连通块且该连通块与x不在同一连通块上
      if (tmp==find(f[tmp]) && x!=find(f[tmp])){
        now_dus = tmp;
        break;
      }
    }
    // 合并为了一个连通块
    if (now_dus==-1) break;
    ans.push_back({i,y,now_dus});
    // 连接now_dus与x两个连通块
    merge(now_dus,x);
    // 返回新合并出的连通块
    dsus.insert(find(f[x]));
  }

  cout<<ans.size()<<endl;
  for (auto [x,y,z]:ans){
    cout<<x<<" "<<y<<" "<<z<<endl;
  }
}

  有建议可以评论,我会积极改进qwq。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cando-01

随心而动,随性而为。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值