Educational Codeforces Round 55 (Rated for Div. 2) ABCD总结

终测前三题900+,终测完三题597,上了35分。总算突破了1700。。。

这次题目简单题来说偏难。A题9分钟才写出来。赛后补了D发现并不是太难。。。

A:一本书有n页,你现在在x页,你要翻到y页,一次只能翻正好d页。可以从第x页翻到第n页或者第1页(即使不够正好d页),再翻到第y页。不能翻到第y页输出-1,否则输出最少翻几次。

只需要分上面三种情况看能否整除取最小值就好了。如果都不能整除就是-1。

B:给你一个只包含'G'和'S'的串,你只能最多交换一次两个字母的位置。求最长连续G序列多长。

统计一下G的总数,维护一下每一个S前面连续多少个G,后面连续多少个G,然后O(n)扫一遍,对于S,考虑能否交换使其左右连接起来。(注意这里是两种情况。)

C:有n个学生,m个课题。给你每个学生所选的课题的编号和能力值。

你要选若干学生,组成人数相同的若干组,每一组学生所选课题相同,且任意两组的课题不能相同。求满足要求的总最大能力值。

用vector保存每个课题的学生的能力值,排序,预处理后缀最大值,枚举每一组学生的总数,然后人数够且后缀>0的课题就可以选了。比赛的时候读错题了,以为每组不超过m个人,害我调了一个小时。。。

D:给你n个整数d[i]>=1,这n个点依次编号1~n,让你构造一个图,使

1、这个图的直径最大

2、这个图连通

3、这n个点的度数都不超过其对应的d[i]

显然尽可能的直径最大,就是先把度不为1的点连成一条链,然后度为1的点可以接在两头,这样直径肯定最大。

然后多余的度为1的点连到度数还没够的点,看看能不能全连上即可。

因此用三个vector,第一个vector保存度为1的点的下标,第二个第三个都是pair,分别保存度和下标,以及相连的点的编号,然后按上面思路写就行了。注意no情况的判断。

代码:

#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
using namespace std;
const int maxn=500+10;
int n,k;
vector<int>yi;
vector< pair<int,int> >duo,ans;
int cnt,tmp,flag;
int d[maxn];
int main()
{

    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&k);
        if(k==1) yi.push_back(i);
        else duo.push_back(mp(k,i));
    }
    if(!duo.size()) {puts("NO");return 0;}
    tmp=duo.size()-1;
    for(int i=0;i<duo.size()-1;i++)
    {
        ans.push_back(mp(duo[i].second,duo[i+1].second));
        d[duo[i].second]++;
        d[duo[i+1].second]++;
    }
    if(yi.size())
    {
        ans.push_back(mp(yi.back(),duo[0].second));
        d[yi.back()]++;
        d[duo[0].second]++;
        yi.pop_back();
        tmp++;
        if(yi.size())
        {
        ans.push_back(mp(yi.back(),duo.back().second));
        d[yi.back()]++;
        d[duo.back().second]++;
        yi.pop_back();
        tmp++;
        }
    }
    int i=0;
    while(yi.size()&&i<duo.size())
    {
        if(d[duo[i].second]<duo[i].first)
        {
            ans.push_back(mp(yi.back(),duo[i].second));
            d[duo[i].second]++;
            yi.pop_back();
        }
        else i++;
    }
    if(yi.size()) {puts("NO");return 0;}
    printf("YES %d\n",tmp);
    printf("%d\n",ans.size());
    for(int i=0;i<ans.size();i++)
    {
        printf("%d %d\n",ans[i].first,ans[i].second);
    }
    return 0;
}

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值