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<<'\n';
    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<<'\n';
    }
    return 0;
}
View Code

 

posted @ 2019-03-10 22:19  heyuhhh  阅读(253)  评论(0编辑  收藏  举报