Codeforces Round #501

Codeforces Round #501

Problem A.Points in Segments
题目概述
给定Ox轴总长度N和线段个数M,并分别给出M个线段所在的区间[l,r]覆盖在Ox轴上,问在轴上还有几个点没有被覆盖并将其罗列出来。数据规模N,M均小于100.

思路:
一个类似于桶排序的思想,用bool数组去做覆盖,模拟这个过程,最后统计并输出即可。

代码A:

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int i,j,n,m,b[1001];
int r()
{
    int ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        ans*=10;
        ans+=ch-'0';
        ch=getchar();
    }
    return ans;
}
int x,y;
int main()
{
    n=r(),m=r();
    for(i=1;i<=n;i++)
    {
        x=r(),y=r();
        for(j=x;j<=y;j++)
        b[j]=1;
    }
    int sum=0;
    for(i=1;i<=m;i++)
    if(!b[i])
    sum++;
    cout<<sum<<endl;
    for(i=1;i<=m;i++)
    if(!b[i])
    cout<<i<<" ";
    return 0;
}

Problem B.Obtaining the String
题目概述
给定两个长度为N(N<=50)的小写字母组成的字符串S,T,可以将S字符串中相邻的ai与ai+1两位互换,求一种可行的互换方式,使得S变为T,若不能则输出-1,若能则输出互换的步数和题干中所描述的“ai与ai+1两位互换”的i。要求总步数不超过10000.

思路:
贪心思想。直接从前往后搜,若Si=Ti则继续向后搜,反之则从S中找到使得Sj=Ti的j,并将Sj转移到Si的位置上,转移时想着记录操作。由于数据规模不大,时间复杂度为ON2,所以可行。

代码B:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
int i,j,n,m;
int c[10001];
char a[51],b[51];
int r()
{
    int ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        ans*=10;
        ans+=ch-'0';
        ch=getchar();
    }
    return ans;
}

int main()
{
    n=r();
    for(i=1;i<=n;i++)
    cin>>a[i];
    for(i=1;i<=n;i++)
    cin>>b[i];

    int j=1,swi=0;
    char x;
    while(j<=n)
    {
        for(i=j;i<=n;i++)
        if(a[i]==b[j])
        {
            for(int k=i;k>j;k--)
            {
                x=a[k];
                a[k]=a[k-1];
                a[k-1]=x; 
                c[++m]=k-1;
            }
            swi=1;
            break;
        }
        if(!swi)
        {
            cout<<-1;
            return 0;
        }
        j++;swi=0;
    }
    cout<<m<<endl;
    for(i=1;i<=m;i++)
    cout<<c[i]<<" ";
    return 0;
}

Problem C.Songs Compression
题目概述
给定N个音乐的原大小和压缩后的大小,现在有一个容量为M的闪存器,需要我们选取几个音乐进行压缩,使得这N个音乐完全被容纳在闪存器中。题目要求压缩的音乐数量尽可能的小,输出最小的个数。

思路:
个人认为比B题简单的贪心,实际上就是把我们现在欠下的容量用压缩掉的体积补回来,所以思路就是对每一个音乐作差,然后排序,让压缩体积大的尽可能的先压缩,之后模拟这个压缩过程直至满足题意,输出个数,如果全部压缩之后仍然不行,则输出-1。

代码C:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
long long i,j,n,m;
struct data
{
    long long x,y,w;
}a[100001];
long long r()
{
    long long ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        ans*=10;
        ans+=ch-'0';
        ch=getchar();
    }
    return ans;
}

long long cmp(data aa,data bb)
{
    if(aa.w>bb.w) return 1;
    return 0;
}
long long sum,sum1;
int main()
{
    n=r(),m=r();
    for(i=1;i<=n;i++)
    {
        a[i].x=r(),a[i].y=r();
        a[i].w=a[i].x-a[i].y;
        sum+=a[i].y;
        sum1+=a[i].x;
    }
    if(sum>m)
    {cout<<-1;
    return 0;}
    sum1-=m;
    if(sum1<=0)
    {cout<<0;
    return 0;}
    long long tot=0;
    sort(a+1,a+n+1,cmp);
    for(i=1;i<=n;i++)
    {
        sum1-=a[i].w;
        tot++;
        if(sum1<=0)
        {cout<<tot;return 0;} 
    }

}
/*
4 14
5 5
4 4
3 3
3 2
*/

Problem D.Walking Between Houses
题目概述
给定一个长度为N的线段,从1出发,不能超过[1,N]的范围,要求在K步以内走完S的距离,每一步的距离即为出发点和结束点的坐标差的绝对值。输出是否能够完成要求,若不能,输出NO,反之输出YES并且输出从第二步开始的坐标。

思路:
一个模拟题,我们可以先尽全力的走,然后一次一步的走。m*(n-1) < s||m > s即为每次都尽全力还走不完和每次只走1步都会超过S的情况。

代码D:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
unsigned long long i,j,n,m,s;

unsigned long long r()
{
    unsigned long long ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        ans*=10;
        ans+=ch-'0';
        ch=getchar();
    }
    return ans;
}

int main()
{
    n=r(),m=r(),s=r();
    if(m*(n-1)<s||m>s)
    {
        cout<<"NO";
        return 0;
    }
    cout<<"YES"<<endl;

    unsigned long long now=1;
    unsigned long long mm=m;
    for(i=1;i<=mm;i++)
    {
        if(now-1>n-now)
        {
            if(now-1>s-m+1)
            now-=s-m+1,s-=s-m+1;
            else
            s-=now-1,now=1;
        }
        else
        {
            if(n-now>s-m+1)
            now+=s-m+1,s-=s-m+1;
            else
            s-=n-now,now=n;
        }
        cout<<now<<" ";
        m--;
    }

    return 0;
}
/*
10 5 6
*/

Problem E1. Stars Drawing (Easy Edition)
题目概述
给定一个N * M的网格,每个格子里为“ * “或” . “,以一个“ * ”为中心向四周均匀发散,四边各发散1个格子组成的十字架形状记为半径为1,以此类推。十字架之间可以重合、有交叉。某张N * M的网格可能是由多个十字架组成,问这个网格能否由多个十字架组成,若能,则输出所有十字架中心的横坐标、纵坐标、半径。N<=100

思路:
暴力做法,找出每个能扩展出一个半径的十字架的中心点,并继续向外扩展,并标记上已经扩展过的点。最后检查为 * 但是没有标记的点,如果存在则输出-1,反之正常输出即可。

代码D:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
int i,j,n,m;
int a[101][101];
int b[101][101],ans[10000][3];
char xx;

int r()
{
    int ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        ans*=10;
        ans+=ch-'0';
        ch=getchar();
    }
    return ans;
}
int tot;
void dfs(int x,int y,int s)
{
    if(s+x<=n&&x-s>0&&a[s+x][y]&&a[x-s][y]
    &&s+y<=m&&y-s>0&&a[x][y+s]&&a[x][y-s])
    b[s+x][y]=b[x-s][y]=b[x][s+y]=b[x][y-s]=0,
    dfs(x,y,s+1);
    else
    ans[++tot][0]=x,ans[tot][1]=y,ans[tot][2]=s-1;
}
int kk;
int main()
{
    n=r(),m=r();
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            xx=getchar();
            if(xx=='*')
            a[i][j]=b[i][j]=1,kk=1;
        }
        getchar();
    }
    if(!kk)
    {
        cout<<0;
        return 0;
    }
    for(i=2;i<n;i++)
    for(j=2;j<m;j++)
    {
        if(a[i][j]&&a[i-1][j]&&a[i+1][j]&&
        a[i][j+1]&&a[i][j-1])
        b[i][j]=b[i-1][j]=b[i+1][j]=b[i][j+1]=b[i][j-1]=0,dfs(i,j,2);
    }

    for(i=1;i<=n;i++)
    for(j=1;j<=m;j++)
    {
        if(b[i][j])
        {cout<<-1;
        return 0;}
    }
    cout<<tot<<endl;
    for(i=1;i<=tot;i++)
    cout<<ans[i][0]<<" "<<ans[i][1]<<" "<<ans[i][2]<<endl;
    return 0;
}
/*
6 8
....*...
...**...
..*****.
...**...
....*...
........
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值