• Codeforces Round #544 (Div. 3) 题解


    Codeforces Round #544 (Div. 3)

    D. Zero Quantity Maximization

    题目链接:https://codeforces.com/contest/1133/problem/D

    题意:

    给出ai,bi,然后让你确定一个数d,令ci=d*ai+bi,问怎么确定这个d,有最多的ci为0。

    题解:

    这个题其实不难,但是我没做起,哎,初中数学没学好啊。。其实做法就是map+pair就行了。

    但是这里要注意一个问题,就是当ai=bi=0的时候,d是可以任意取值的,可以对其它情况下ci为0的个数作贡献。就是这里坑了我好久。

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5+5;
    ll a[N],b[N],c[N],d[N],f[N];
    ll n,k;
    map <pair<ll,ll>,ll>mp;
    int main(){
        ios::sync_with_stdio(false);cin.tie(0);
        cin>>n;
        int ans=0;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=n;i++) cin>>b[i];
        int cnt = 0;
        for(int i=1;i<=n;i++){
            ll g=__gcd(abs(a[i]),abs(b[i]));
            if(b[i]==0 && a[i]==0){
                cnt++;
                continue ;
            }else if(b[i]==0){
                ans++;
                continue ;
            }else if(a[i]==0){
                continue ;
            }
            a[i]/=g;b[i]/=g;
            c[i]=abs(a[i]);d[i]=abs(b[i]);
            if((a[i]<0&&b[i]>0) ||(a[i]>0&&b[i]<0)){
                c[i]=-c[i],d[i]=abs(d[i]);
            }
        }
        for(int i=1;i<=n;i++){
            if(b[i]==0||a[i]==0) continue ;
            mp[make_pair(c[i],d[i])]++;
            if(mp[make_pair(c[i],d[i])]>ans){
                ans=mp[make_pair(c[i],d[i])];
            }
        }
        cout<<ans+cnt;
        return 0;
    }
    View Code

    E. K Balanced Teams

    题目链接:https://codeforces.com/contest/1133/problem/E

    题意:

    给出n个人的姿势水平ai,然后让你最多分成k个组,并且满足每个组里面人的姿势水平相差不超过5,问最多能分多少个学生在组里面。

    题解:

    排下序然后考虑动态规划。到第i个学生的时候,他可以不被加入分组中,也可以和前面的人一组,设dp[i][j]为前i个人,划分j组时最多的学生。

    那么转移就是dp[i][j]=max{dp[i-1][j],dp[k][j-1]+i-k+1}。这里k是往前枚举的,但是其实并不需要这么枚举,只需要找到>=ai-5的第一个位置,从那个位置转移就行了。假设那个位置为p,之后从p+x转移答案不会比从p转移更优的。这个自己yy一下应该还是比较容易相通的吧。

    具体见代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 5005;
    int n,k;
    int a[N];
    int dp[N][N],l[N];
    int main(){
        ios::sync_with_stdio(false);cin.tie(0);
        cin>>n>>k;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++){
            int tmp = lower_bound(a+1,a+n+1,a[i]-5)-a;
            l[i]=tmp-1;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=i;j++){
                dp[i][j]=dp[i-1][j];
                dp[i][j]=max(dp[i][j],dp[l[i]][j-1]+i-l[i]);
            }
        }
        int ans = 0;
        for(int i=1;i<=k;i++) ans=max(ans,dp[n][i]);
        cout<<ans;
        return 0;
    }
    View Code

    F1. Spanning Tree with Maximum Degree

    题目链接:https://codeforces.com/contest/1133/problem/F1

    题意:

    给出一个无向图,然后让你求出这个无向图度数最大的一颗生成树。

    题解:

    找到度数最大的那个点,然后先把与这个点相连的那些边全部加入生成树中,最后再求生成树就好了。

    证明的话,可以这样想,假如我们选的点是u,有两个与其相连的点为v1,v2,假如v1与v2孤立,那么<u,v1>与<u,v2>加入生成树肯定没问题的;如果v1与v2不经过u可以连通,那么<u,v1>,<u,v2>加入生成树中也没问题,不会出现最后没有生成树的情况(自己yy一下吧,感觉有点说不清楚)。

    具体见代码吧:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5+5;
    int n,m;
    struct Edge{
        int u,v,w;
        bool operator < (const Edge &A)const{
            return w<A.w;
        }
    }e[N];
    int f[N],d[N],vis[N];
    int find(int x){
        return f[x]==x?f[x]:f[x]=find(f[x]);
    }
    int main(){
        ios::sync_with_stdio(false);cin.tie(0);
        cin>>n>>m;
        int mx=0,p;
        for(int i=1;i<=m;i++){
            int u,v;
            cin>>u>>v;
            e[i].u=u;e[i].v=v;
            d[u]++;d[v]++;
            if(d[u]>mx){
                mx=d[u];
                p=u;
            }
            if(d[v]>mx){
                mx=d[v];
                p=v;
            }
        }
        for(int i=0;i<=n+1;i++) f[i]=i;
        for(int i=1;i<=m;i++){
            int u=e[i].u,v=e[i].v;
            if(u==p||v==p){
                int fx=find(u),fy=find(v);
                f[fx]=fy;vis[i]=1;
            }
        }
        for(int i=1;i<=m;i++){
            int fx=find(e[i].u),fy=find(e[i].v);
            if(fx==fy) continue ;
            f[fx]=fy;vis[i]=1;
        }
        for(int i=1;i<=m;i++) if(vis[i]) cout<<e[i].u<<" "<<e[i].v<<'
    ';
        return 0;
    }
    View Code

    F2. Spanning Tree with One Fixed Degree

    题目链接:https://codeforces.com/contest/1133/problem/F2

    题意:

    给出一个无向图和D,要求你求出一颗1结点度数为D的生成树。

    题解:

    思想还是类似于上面一道题吧,考虑所有与1结点连边的边。我们首先考虑那些必须加入的边,什么边算作必须加入的呢?

    假如我们先不考虑与1相连的边,在其它点中求生成树,那么最后会形成一个森林,每个连通块都需要一条边与1号结点相连。通过这个就比较容易计算出必须加入的边。

    然后再根据具体D的值,考虑加入与1号点相连的其它边,这样并不会影响它最终是否会形成一个生成树。

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5+5;
    int n,m,k;
    struct Edge{
        int u,v;
    }e[N];
    int f[N],vis[N];
    int find(int x){
        return f[x]==x?f[x]:f[x]=find(f[x]);
    }
    void init(){
        for(int i=0;i<=n;i++) f[i]=i;
    }
    
    int main(){
        //ios::sync_with_stdio(false);cin.tie(0);
        cin>>n>>m>>k;
        init();
        for(int i=1;i<=m;i++){
            int u,v;
            cin>>u>>v;
            e[i].u=u;e[i].v=v;
            if(u==1 || v==1) continue ;
            int fx=find(u),fy=find(v);
            if(fx==fy) continue ;
            f[fx]=fy;
        }
        int need = 0;
        for(int i=1;i<=m;i++){
            int u=e[i].u,v=e[i].v;
            if(u==1 ||v==1){
                int fx=find(u),fy=find(v);
                if(fx!=fy){
                    f[fx]=fy;
                    need++;
                    vis[i]=2;
                }else{
                    vis[i]=1;
                }
            }
        }
        if(need>k) return puts("NO"),0;
        k-=need;
        init();
        for(int i=1;i<=m;i++){
            if(vis[i]!=2) continue ;
            int u=e[i].u,v=e[i].v;
            int fx=find(u),fy=find(v);
            f[fx]=fy;
        }
        for(int i=1;i<=m;i++){
            if(k==0) break ;
            if(vis[i]==1){
                k--;
                int u=e[i].u,v=e[i].v;
                int fx=find(u),fy=find(v);
                f[fx]=fy;
                vis[i]=3;
            }
        }
        if(k>0) return puts("NO"),0;
        puts("YES");
        for(int i=1;i<=m;i++){
            if(e[i].u==1 || e[i].v==1) continue ;
            int fx=find(e[i].u),fy=find(e[i].v);
            if(fx!=fy){
                f[fx]=fy;
                vis[i]=3;
            }
        }
        for(int i=1;i<=m;i++){
            if(vis[i]>=2) cout<<e[i].u<<" "<<e[i].v<<'
    ';
        }
        return 0;
    }
    View Code
  • 相关阅读:
    异步文档树解决方案
    兼容IE低版本的文件上传解决方案
    CentOS-常用命令(版本:7.x)
    搭建Nexus3私服(含使用说明,支持CentOS、Windows)
    CentOS-搭建MinIO集群
    GitLab升级(yum安装版v11.11.8~12.0.12)
    yum安装GitLab-v11.11.8(git私服)
    Docker中容器的备份和恢复(可迁移)
    Nexus3配置yum私服
    局域网连接数据慢的方法汇总
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/10507674.html
Copyright © 2020-2023  润新知