【Codeforces Round #544 (Div. 3)】 A.B.C.D.E.F1.F2.

前言

这场由于大号都不算分,于是开新号打,开场还算顺利,但是由于D题的坑点较多,有点慌,导致E题也开始乱提交,最后没时间做F2。打div3打成这样是不应该的。

biu-biubiu r a t i n g + = 168 rating+=168 rating+=168 1500->1668


A. Middle of the Contest

题意

输出两个时间的中间时间。

做法

由于两个时间在同一天,直接转换成分钟取平均值就可以。

代码

#include<stdio.h>
int main()
{
    int h1,m1,h2,m2;
    scanf("%d:%d",&h1,&m1);
    scanf("%d:%d",&h2,&m2);
    printf("%02d:%02d\n",(h1*30+h2*30+(m1+m2)/2)/60,(h1*30+h2*30+(m1+m2)/2)%60);
    return 0;
}


B. Preparation for International Women’s Day

题意

给你n个数,两个数成对取出,求最多可以取出多少对和是k的倍数。

1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1n2×105
1 ≤ k ≤ 100 1 \leq k \leq 100 1k100

做法

对于每个数只保存对k取模之后的余数即可,之后对于每个余数与对应的余数匹配即可。
要特判 0 0 0和余数等于 k / 2 k/2 k/2的时候。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 2e5+5;
int d[maxn];
int sum[maxn];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&d[i]);
        sum[d[i]%k]++;
    }
    int ans=sum[0]/2;
    for(int i=1;i<=k/2;i++)
    {
        if(i==k-i) ans=ans+sum[i]/2;
        else ans=ans+min(sum[i],sum[k-i]);
    }
    printf("%d\n",ans*2);
    return 0;
}


C. Balanced Team

题意

给你 n n n个数字,从中选出尽量多的数字,使这些数中最大值与最小值的差不超过 5 5 5.

做法

首先将数组排序,二分找到每个值能向右伸展的最长长度即可。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 2e5+5;
int a[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    int ans=1;
    for(int i=1;i<=n;i++)
    {
        int pos=upper_bound(a+1,a+1+n,a[i]+5)-a;
        ans=max(ans,pos-i);
    }
    printf("%d\n",ans);
    return 0;
}


D. Zero Quantity Maximization

题意

给你两个长度为 n n n的数组 a a a, b b b c i = a i × d + b i c_i = a_i \times d +b_i ci=ai×d+bi,现在找到一个 d d d使尽量多的 c i c_i ci 0 0 0
1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105
− 1 0 9 ≤ a i , b i ≤ 1 0 9 -10^9 \leq a_i,b_i \leq10^9 109ai,bi109
做法

c i = 0 c_i=0 ci=0,那么 d = − b i a i d=-\frac{b_i}{a_i} d=aibi,只需要看哪个d出现次数最多即可,这里我怕被卡精度,于是存分数约分后的最简形式即可,这里要注意 a i = 0 , b i = 0 a_i=0,b_i=0 ai=0,bi=0等情况。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef pair<int,int> pii;
const int maxn = 2e5+5;
map<pii,int> mp;
int a[maxn],b[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    int ans=0;
    int tmp=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==0&&b[i]==0)
        {
            tmp++;
            continue;
        }
        else if(a[i]==0) continue;
        if(b[i]==0)
        {
            mp[pii(0,1)]++;
            ans=max(ans,mp[pii(0,1)]);
            continue;
        }
        int up=-b[i]/__gcd(a[i],b[i]);
        int down=a[i]/__gcd(a[i],b[i]);
        if(up<0)
        {
            up=up*-1;
            down=down*-1;
        }
        mp[pii(up,down)]++;
        ans=max(ans,mp[pii(up,down)]);
    }
    printf("%d\n",ans+tmp);
    return 0;
}


E. K Balanced Teams

题意

给你n个数,分成k组,要求每组内最大值与最小值的差值不超过5。求k组最多可以放多少个数。

1 ≤ n , k ≤ 5000 1 \leq n,k \leq 5000 1n,k5000
做法

首先对数组排序,我们可以预处理每个数最多可以向左扩展的长度。
之后我们用 d p [ i ] [ j ] dp[i][j] dp[i][j]表示前i个数分为j组最多可以放多少个数。
对于每个i,一定是从之前预处理的位置转移过来,因为一段应该放尽量多的值。
我们设位置 i i i能够扩展的最左位置为 l [ i ] l[i] l[i]。那么转移方程为:
d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] , d p [ l [ i ] − 1 ] [ j − 1 ] + i − l [ i ] + 1 ) dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[l[i]-1][j-1]+i-l[i]+1) dp[i][j]=max(dp[i1][j],dp[i][j1],dp[l[i]1][j1]+il[i]+1)
最后 d p [ n ] [ k ] dp[n][k] dp[n][k]便是答案。
代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 5005;
int a[maxn],l[maxn];
int dp[maxn][maxn];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    dp[0][0]=0;
    for(int i=1;i<=n;i++) l[i]=lower_bound(a+1,a+1+n,a[i]-5)-a;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            dp[i][j]=max(dp[i][j],dp[l[i]-1][j-1]+i-l[i]+1);
        }
    }
    printf("%d\n",dp[n][k]);
    return 0;
}


F1. Spanning Tree with Maximum Degree

题意

给你 n n n个点 m m m条边的无向联通图,找出一棵生成树,使度最大的点的度最大。

1 ≤ n , m ≤ 1 0 5 1 \leq n,m \leq 10^5 1n,m105
做法

首先度最大的点一定等于原图中度最大的点的度,那么我们只需要找到原图中度最大的点,由这个点向外 b f s bfs bfs即可。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef pair <int, int> pii;
const int maxn = 2e5+5;
#define Se second
#define Fi first
#define pb push_back
int vis[maxn];
vector<int>G[maxn];
vector<pii> ans;
int in[maxn];
void bfs(int rt)
{
    vis[rt]=1;
    queue<int> q;
    q.push(rt);
    while(!q.empty())
    {
        int tp=q.front();
        q.pop();
        for(int i=0;i<G[tp].size();i++)
        {
            int to=G[tp][i];
            if(vis[to]) continue;
            vis[to]=1;
            ans.pb(pii(tp,to));
            q.push(to);
        }
    }
}
int main()
{
    int u,v,n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        G[u].pb(v);
        G[v].pb(u);
        in[u]++;
        in[v]++;
    }
    int maxx=0;
    int pos=0;
    for(int i=1;i<=n;i++)
    {
        if(in[i]>maxx)
        {
            maxx=in[i];
            pos=i;
        }
    }
    bfs(pos);
    for(int i=0;i<ans.size();i++) printf("%d %d\n",ans[i].Fi,ans[i].Se);
    return 0;
}


F2. Spanning Tree with One Fixed Degree

题意

给你 n n n个点 m m m条边的无向联通图,找出一棵生成树,使 1 1 1这个点的度 = d =d =d

1 ≤ n , m ≤ 1 0 5 1 \leq n,m \leq 10^5 1n,m105
做法

首先我们把 1 1 1这个点先拿出来,如果 1 1 1的度最初就小于 d d d,答案一定不存在,否则对除 1 1 1这个点之外剩下的图求连通分量,并记录每个连通分量之内有哪些点与 1 1 1相连,之后为保证联通,每个连通分量一定至少和 1 1 1连一条边,之后如果此时 1 1 1的度已经超过 d d d,则答案不存在,否则将多余的度与那些之前没连过而且与 1 1 1有边的点相连即可。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<string.h>
using namespace std;
typedef pair <int, int> pii;
const int maxn = 2e5+5;
#define Se second
#define Fi first
#define pb push_back
vector<int>G[maxn];
vector<int>dsu[maxn];
vector<int>one[maxn];
vector<pii> ans;
int n,m,d,in[maxn];
int vis[maxn];
int tot;
void dfs(int x)
{
    dsu[tot].pb(x);
    vis[x]=1;
    for(int i=0;i<G[x].size();i++)
    {
        int to=G[x][i];
        if(vis[to]) continue;
        if(to==1)
        {
            one[tot].pb(x);
            continue;
        }
        dfs(to);
    }
}
int main()
{
    int u,v;
    scanf("%d%d%d",&n,&m,&d);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        in[u]++;
        in[v]++;
        G[u].pb(v);
        G[v].pb(u);
    }
    if(in[1]<d)  return 0*puts("NO");
    for(int i=2;i<=n;i++)
    {
        if(!vis[i])
        {
            ++tot;
            dfs(i);
        }
    }
    if(tot>d) return 0*puts("NO");
    memset(vis,0,sizeof(vis));
    queue<int> q;
    vis[1]=1;
    for(int i=1;i<=tot;i++)
    {
        int b=one[i].back();
        ans.pb(pii(1,b));
        vis[b]=1;
        q.push(b);
        one[i].pop_back();
        d--;
    }
    for(int i=1;i<=tot;i++)
    {
        while(d>0&&one[i].size()>0)
        {
            int b=one[i].back();
            ans.pb(pii(1,b));
            vis[b]=1;
            q.push(b);
            one[i].pop_back();
            d--;
        }
    }
    while(!q.empty())
    {
        int tp=q.front();
        q.pop();
        for(int i=0;i<G[tp].size();i++)
        {
            int to=G[tp][i];
            if(vis[to]) continue;
            ans.pb(pii(tp,to));
            vis[to]=1;
            q.push(to);
        }
    }
    puts("YES");
    for(int i=0;i<ans.size();i++) printf("%d %d\n",ans[i].Fi,ans[i].Se);
    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值