Codeforces Round #522 (Div. 2, based on Technocup 2019 Elimination Round 3)

前言

下午去东农校赛之后晚上来打的这场div2,本来就很困这场还偏偏在12.05开始,但是顶着之前一场不落的flag还是打了下来,开场很小心的写A,B,写了好久之后发现交完AB排名竟如此靠前,之后去开C,感觉不太容易,这是刷一下榜发现学弟只过D分数比我还高,于是选择去看D,看懂题意后发现是个水题,交上去1A,rank60多,上紫稳了。之后噩梦就开始了,一阵阵的502预示着这场将会unrated,最后果不其然,unrated,就这样中国玩家玩到2.30,等来unrated,虽然心情不好,但是题解还是要补的。O(∩_∩)O


A. Kitchen Utensils

题意

给你n个剩余餐具,共有k个人,之前每个人的餐具的套数都是相同的,每套餐具由几个不同的餐具,现在的n个餐具是被偷之后剩下的,问最少被偷走多少餐具。

做法

一套餐具肯定最少包含所有种类的餐具,之后看一个人最少几套餐具就可以了。

代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int num[maxn];
int main()
{
    int n,k,x;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        num[x]++;
    }
    int ans=0;
    int sum=0;
    for(int i=1;i<=100;i++)
    {
        if(num[i]>=1) sum++;
        int tmp=(num[i]/k)+(num[i]%k!=0);
        ans=max(ans,tmp);//tmp为一个人最少可能的餐具数
    }
    printf("%d\n",sum*k*ans-n);
    return 0;
}

B. Personalized Cup

题意

给你一片文章,让你把每个字符放在一个ab的网格中,每一个位置可以是或者字符,要求为行数不超过5,列数不超过20,每相邻两行之间的*数量不能超过1.求满足条件的矩阵中行数最少的,行数相同取列最少的

做法

由于最多五行,那么只要枚举行数,判断是否满足条件即可,满足即跳出。

坑点

要注意每行最多放一个*,因为只有最后多余的那列可能会出现空
细节比较多,实现要小心

代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 105;
char str[maxn];
char pic[maxn][maxn];
int main()
{
    scanf("%s",str);
    int len=strlen(str);
    int flag=1;
    for(int i=1;i<=5;i++)
    {
        if((len%i)<=i&&(len/i+(len%i!=0))<=20)
        {
            flag=i;
            break;
        }
    }
    int tmp=len/flag+(len%flag!=0);
    int yu=tmp*flag-len;
    int cnt=0;
    for(int i=1;i<=yu;i++)//先将带星号的行填上
    {
        for(int k=1;k<=tmp-1;k++)
        {
            pic[i][k]=str[cnt++];
        }
        pic[i][tmp]='*';
    }
    for(int i=yu+1;i<=flag;i++)//填上不带星号的行
    {
        for(int k=1;k<=tmp;k++)
        {
            pic[i][k]=str[cnt++];
        }
    }
    printf("%d %d\n",flag,tmp);
    for(int i=1;i<=flag;i++)
    {
        for(int j=1;j<=tmp;j++)
        {
            printf("%c",pic[i][j]);
        }
        printf("\n");
    }
    return 0;
}

C. Playing Piano

题意

给你一个a数组,让你按照规则构造b数组
规则如下
如果 a i &lt; a i + 1 a_i&lt;a_{i+1} ai<ai+1那么 b i &lt; b i + 1 b_i&lt;b_{i+1} bi<bi+1
如果 a i &gt; a i + 1 a_i&gt;a_{i+1} ai>ai+1那么 b i &gt; b i + 1 b_i&gt;b_{i+1} bi>bi+1
如果 a i = a i + 1 a_i=a_{i+1} ai=ai+1那么 b i ! = b i + 1 b_i!=b_{i+1} bi!=bi+1
给出b数组或者输出-1表示b数组不存在。

做法
考虑一下会发现只有两种情况会出现-1

第一种:连续上升/下降的个数>=6个
第二种:连续五个上升/下降,连续五个下降/上升
先用枚举的方法处理掉-1的情况
不是-1的情况一定是有很多解的,直接爆搜61ms就过掉了。
目前不清楚能不能卡掉爆搜。

代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int b[maxn];
int n,ok;
void dfs(int pos)
{
    if(ok==1) return ;
    if(pos==1)
    {
        for(int i=1;i<=5;i++)
        {
            b[pos]=i;
            dfs(pos+1);
            if(ok==1) return;
        }
    }
    else if(pos==n+1)
    {
        ok=1;
        return ;
    }
    else
    {
        if(a[pos]==a[pos-1])
        {
            for(int i=1;i<=5;i++)
            {
                if(b[pos-1]!=i)
                {
                    b[pos]=i;
                    dfs(pos+1);
                    if(ok) return ;
                }
            }
        }
        else if(a[pos]<a[pos-1])
        {
            for(int i=b[pos-1]-1;i>=1;i--)
            {
                b[pos]=i;
                dfs(pos+1);
                if(ok) return ;
            }
        }
        else
        {
            for(int i=b[pos-1]+1;i<=5;i++)
            {
                b[pos]=i;
                dfs(pos+1);
                if(ok) return ;
            }
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    if(n==1)
    {
        printf("1\n");
        return 0;
    }
    if(n==2)
    {
        if(a[1]<=a[2]) printf("1 2\n");
        else if(a[1]>a[2]) printf("2 1\n");
        return 0;
    }
    for(int i=1;i<=n-5;i++)//判断1 2 3 4 5 6
    {
        int flag=0;
        for(int j=i;j<=i+4;j++)
        {
            if(a[j]>=a[j+1]) flag=1;
        }
        if(flag==0)
        {
            printf("-1\n");
            return 0;
        }
    }
    for(int i=1;i<=n-5;i++)//判断6 5 4 3 2 1
    {
        int flag=0;
        for(int j=i;j<=i+4;j++)
        {
            if(a[j]<=a[j+1]) flag=1;
        }
        if(flag==0)
        {
            printf("-1\n");
            return 0;
        }
    }
    for(int i=1;i<=n-9;i++)//判断1 2 3 4 5 5 4 3 2 1
    {
        int flag=0;
        for(int j=i;j<=i+3;j++)
        {
            if(a[j]>=a[j+1]) flag=1;
        }
        if(a[i+4]!=a[i+5]) flag=1;
        for(int j=i+5;j<=i+8;j++)
        {
            if(a[j]<=a[j+1]) flag=1;
        }
        if(flag==0)
        {
           if(flag==0)
            {
                printf("-1\n");
                return 0;
            }
        }
    }
     for(int i=1;i<=n-9;i++)//判断5 4 3 2 1 1 2 3 4 5
    {
        int flag=0;
        for(int j=i;j<=i+3;j++)
        {
            if(a[j]<=a[j+1]) flag=1;
        }
        if(a[i+4]!=a[i+5]) flag=1;
        for(int j=i+5;j<=i+8;j++)
        {
            if(a[j]>=a[j+1]) flag=1;
        }
        if(flag==0)
        {
           if(flag==0)
            {
                printf("-1\n");
                return 0;
            }
        }
    }
    dfs(1);
    for(int i=1;i<=n;i++) printf("%d ",b[i]);
    return 0;
}


D. Barcelonian Distance

题意

给你一条二维平面上的直线,给你两个点,问从A点走到B点的最短路径
点只能在给定直线和与坐标轴平行的直线上行走。

做法

如果不经过直线,一定直接是曼哈顿距离
如果经过直线,一定是A沿直线走到直线上最优,从直线上延直线走到B最优
而从A直接走到给定直线有两种走法,从给定直线走到B有两种走法
所以只要判断上述5种走法的最小值即可。

坑点

给定直线斜率为0时注意要特判,斜率为0或者inf,那么就是曼哈顿距离

代码

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
double dis(double a,double b,double c,double d)
{
    return sqrt((a-c)*(a-c)+(b-d)*(b-d));
}
int main()
{
    ll a,b,c,x_1,y_1,x_2,y_2;
    scanf("%lld%lld%lld",&a,&b,&c);
    scanf("%lld%lld%lld%lld",&x_1,&y_1,&x_2,&y_2);

    double ans,ans1,xx1,yy1,xx2,yy2;
    //曼哈顿距离
    ans=1.0*(abs(x_2-x_1)+abs(y_2-y_1));

    //x 1 y 1
    ans1=0;
    xx1=1.0*x_1;
    yy1=-1.0*(1.0*a*x_1+c)*(1.0/b);
    xx2=1.0*x_2;
    yy2=-1.0*(1.0*a*x_2+c)*(1.0/b);
    ans1+=fabs(yy1-y_1)+fabs(yy2-y_2);
    ans1+=dis(xx1,yy1,xx2,yy2);
    ans=min(ans,ans1);

     //x 1 y 0
    ans1=0;
    xx1=1.0*x_1;
    yy1=-1.0*(1.0*a*x_1+c)*(1.0/b);
    xx2=-1.0*(1.0*b*y_2+c)*(1.0/a);
    yy2=1.0*y_2;
    ans1+=fabs(yy1-y_1)+fabs(xx2-x_2);
    ans1+=dis(xx1,yy1,xx2,yy2);
    ans=min(ans,ans1);

     //x 0 y 0
    ans1=0;
    xx1=-1.0*(1.0*b*y_1+c)*(1.0/a);
    yy1=1.0*y_1;
    xx2=-1.0*(1.0*b*y_2+c)*(1.0/a);
    yy2=1.0*y_2;
    ans1+=fabs(xx1-x_1)+fabs(xx2-x_2);
    ans1+=dis(xx1,yy1,xx2,yy2);
    ans=min(ans,ans1);

    //x 0 y 1
    ans1=0;
    xx1=-1.0*(1.0*b*y_1+c)*(1.0/a);
    yy1=1.0*y_1;
    xx2=1.0*x_2;
    yy2=-1.0*(1.0*a*x_2+c)*(1.0/b);
    ans1+=fabs(xx1-x_1)+fabs(yy2-y_2);
    ans1+=dis(xx1,yy1,xx2,yy2);
    ans=min(ans,ans1);

    printf("%.10f\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值