AtCoder Beginner Contest 469 题解

D - The Big Two

没有怎么思考,写法可能比较暴力。

  • 容易发现对于第一场比赛,设晋级的为 \(u\)\(v\),那么合法的组一定是 \((u,x) / (v,x)\)
  • 我们分开处理,以 \(u\) 为例,遍历找到第一场没有出现 \(u\) 的比赛,设该场比赛出现的是 \(s,t\)
  • 那么答案只能是 \((u,s)/(u,t)\) ,再次遍历分别判断即可。
  • 注意如果 \((u,v)\) 是合法情况会重复计算,记得减去。
点击查看代码
#include<bits/stdc++.h>

using namespace std;


using ll=long long;
using pii=pair<int,int>;

#define x first 
#define y second 

const int N=8e5+10,inf=0x3f3f3f3f,mod=998244353;

int n,m,q;
pii a[N];

void solve() {
    cin>>n>>m;

    int res=0;

    for(int i=1;i<=m;i++) {
        cin>>a[i].x>>a[i].y;
    }
    int u=a[1].x,v=a[1].y;

    int s=0,t=0;
    for(int i=1;i<=m;i++) {
        if(a[i].x!=u && a[i].y!=u) {
            s=a[i].x,t=a[i].y;
        } 
    }

    if(!s) res+=n-1;
    else {
        // u s
        bool sg=0;
        for(int i=1;i<=m;i++) {
            if(a[i].x!=u && a[i].y!=u && a[i].x!=s && a[i].y!=s) {
                sg=1;
                break;
            }
        }

        if(!sg) res++;

        //u t
        sg=0;
        for(int i=1;i<=m;i++) {
            if(a[i].x!=u && a[i].y!=u && a[i].x!=t && a[i].y!=t) {
                sg=1;
                break;
            }
        }

        if(!sg) res++;
    }
    // cout<<u<<" "<<s<<":"<<t<<"\n";

    s=0,t=0;

    for(int i=1;i<=m;i++) {
        if(a[i].x!=v && a[i].y!=v) {
            s=a[i].x,t=a[i].y;
        } 
    }

    if(!s) res+=n-1;
    else {
        // v s
        bool sg=0;
        // cout<<v<<"--"<<s<<"\n";
        for(int i=1;i<=m;i++) {
            if(a[i].x!=v && a[i].y!=v && a[i].x!=s && a[i].y!=s) {
                sg=1;
                break;
            }
        }

        if(!sg) res++;

        //v t
        sg=0;
        for(int i=1;i<=m;i++) {
            if(a[i].x!=v && a[i].y!=v && a[i].x!=t && a[i].y!=t) {
                sg=1;
                break;
            }
        }

        if(!sg) res++;
    }

    bool sg=0;
    for(int i=1;i<=m;i++) {
        if(a[i].x!=v && a[i].y!=v && a[i].x!=u && a[i].y!=u) {
            sg=1;
            break;
        }
    }
    // cout<<res<<"\n";
    if(!sg) res--;

    cout<<res<<"\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;T=1;
    while(T--) solve();
    return 0;
}

/*
1
3 3 2
1 2 2
2 3 3
3 1 4
2 1
1 1
*/

E - Pro Exam Eligibility

  • 我们只关心一个区间内 'o' 的数量,将所有为 \(o\) 的点提出,设第 \(i\) 个的位置为 \(P_i\)
  • 显然答案具有单调性,考虑二分答案。
  • 对于一个 \(mid\) 合法的条件是存在一个区间 \([i,j]\) ,满足 \((j-i+1)/(P_i-P_j)>=mid\)
  • 分离参数得 \((P_j*mid-j)-(P_i*mid-i)<=1-mid\)
  • 枚举 \(j\) ,记录最小的 \(P_i*mid-i\) 即可。
点击查看代码
#include<bits/stdc++.h>

using namespace std;


using ll=long long;
using pii=pair<int,int>;

#define x first 
#define y second 

const int N=8e5+10,inf=0x3f3f3f3f,mod=998244353;
const double eps=1e-10;

int n,k,q;
pii a[N];
string s;
vector<int> vec;

bool chk(double x) {
    double maxx=0.0;
    int m=vec.size();
    for(int i=k-1;i<m;i++) {
        int nj=i-k+1;
        maxx=max(maxx,vec[nj]*x-nj);
        double now=vec[i]*x-i;
        if(now-maxx<=1.0-x) return 1; 
    }
    return 0;
}


void solve() {
    cin>>n>>k;
    cin>>s;
    s=" "+s;
    for(int i=1;i<=n;i++) {
        if(s[i]=='o') vec.push_back(i);
    }

    double l=0.0,r=1.0;
    while(r-l>eps) {
        double mid=(l+r)/2;
        if(chk(mid)) l=mid;
        else r=mid;
    }

    cout<<fixed<<setprecision(10)<<l<<"\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;T=1;
    while(T--) solve();
    return 0;
}

/*
1
3 3 2
1 2 2
2 3 3
3 1 4
2 1
1 1
*/

F - GCD Maximum Spanning Tree

感觉有点典

  • 易知最大权值不超过 \(max{(a_i)}\),设为 \(mx\)
  • 考虑 Kruskal 的连边思想,先把权值都为 \(val\) 的点连边,因为与它们相连的点最大权值不会超过 \(val\)
  • 然后 \(mx\) 倒叙枚举,枚举 \(val=ki\) 的点,如果没有连在一起就相连,因为倒叙枚举,所以它们之间的 \(\gcd\) 一定是 \(i\) ,贡献为 \(i\)
  • 连边合并用并查集维护即可
点击查看代码
#include<bits/stdc++.h>

using namespace std;


using ll=long long;
using pii=pair<int,int>;

#define x first 
#define y second 

const int N=1e6+10,inf=0x3f3f3f3f,mod=998244353;
const double eps=1e-10;

int n,k,q;
int a[N],p[N];
string s;
vector<int> vec[N];


inline int find(int x) {
    return p[x]==x?p[x]:p[x]=find(p[x]);
}

bool merge(int a,int b) {
    a=find(a),b=find(b);
    if(a==b) return 0;
    p[b]=a;
    return 1;
}

void solve() {
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) vec[a[i]].push_back(i);
    int mx=0;
    for(int i=1;i<=n;i++) mx=max(a[i],mx);
    for(int i=1;i<=mx;i++) p[i]=i;

    ll res=0;
    for(int i=1;i<=mx;i++) {
        if(vec[i].size()) {
            res+=1ll*(vec[i].size()-1)*i;
        }
    }

    for(int i=mx;i>=1;i--) {
        int fi=0;
        for(int j=i;j<=mx;j+=i) {
            if(vec[j].size() && !fi)  fi=j;
            else {
                if(vec[j].size()) {
                    // merge(j,fi);
                    if(merge(j,fi)) res+=i;
                    // cout<<i<<"-"<<res<<"\n";
                }
            }
        }
    }

    cout<<res<<"\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;T=1;
    while(T--) solve();
    return 0;
}

/*
1
3 3 2
1 2 2
2 3 3
3 1 4
2 1
1 1
*/
posted @ 2026-08-02 19:47  Bulyly  阅读(17)  评论(0)    收藏  举报