Codeforces Round 568 部分题解

A
原题链接:https://codeforces.com/contest/1185/problem/A
题意:
有一个无限长的坐标轴,上面站了3个人,题目输入a,b,c,d;分别代表三个人站的位置a,b,c,以及要求两人之间间隔的最小距离d;你可以让这三个随意走动,求最少走多少距离,可以满足任意两个人之间的距离大于等于d;
题解;
只要中间的人不动,若两边的人与中间的人的距离小于d,则往远离中间的人的方向走,直至距离恰好为d。这样走额的距离最小。
AC代码:

#include <bits/stdc++.h>

using namespace std;
int a[3];
int main()
{
	ios::sync_with_stdio(false);
    cin.tie(0);
   	cout.tie(0);
   	int d;
    cin>>a[0]>>a[1]>>a[2]>>d;
    sort(a,a+3);
    int d1=a[1]-a[0];
    int d2=a[2]-a[1];
    int ans=0;
    if(d1<d)ans+=d-d1;
    if(d2<d)ans+=d-d2;
    cout<<ans;
	return 0;
}

B
原题链接:https://codeforces.com/contest/1185/problem/B
题意:
由两个字符串s和t,s是原字符串,t为接收到的字符串,由于中间过程除了某些问题,所以t中字符串可能会接受到多余的字符,但是一定不会少,而且多余的字符相当于是s【i】被发送了多次。
例如:hello 可以变成 hheeelloo,但是不能变成hllo,habcd,helo等。
题解:
对于s中的每处字符,分析该字符连续出现的次数
例如 hello 就是h-1、e-1、l-2、o-1;//字符-连续出现的次数
那么对于t来说则必须要求:
顺序不能变,而且字符出现次数要大于等于s种对应位置字符出现的次数。
任一要求不满足,则输出NO。
都满足,则输出YES。

AC代码:

#include <bits/stdc++.h>

using namespace std;


const int maxn=1e6+5;

int ch[maxn],num[maxn];
int cnt=0;
int main()
{
	ios::sync_with_stdio(false);
    cin.tie(0);
   	cout.tie(0);
    int n;
    cin>>n;
    string s,t;
    bool f=true;
    while(n--)
    {
        cin>>s>>t;
        f=true;
        int ls=s.length();
        int lt=t.length();
        cnt =0;
        ch[cnt]=s[0]-'a';
        num[cnt]=1;
        for(int i=1;i<ls;i++)
        {
            if(s[i]==s[i-1])
            {
                num[cnt]++;//若连续,则数量加一
            }
            else
            {
                ch[++cnt]=s[i]-'a';//不连续,则位置加一
                num[cnt]=1;//数量置为1
            }
        }
        int pos=0;
        int lc=t[0]-'a';
        int sum=1;
        for(int i=1;i<lt;i++)
        {
            if(t[i]==t[i-1])
            {
                sum++;//若连续,则数量加一
            }
            else//不连续
            {
                if(lc!=ch[pos]||sum<num[pos])//字符不相同,或者数量比s串小,则不满足要求
                {
                    f=false;
                    break;
                }
                else
                {
                    lc=t[i]-'a';//与上面s串处理相同
                    sum=1;//数量置为1
                    pos++;//位置加一
                }
            }
        }
        //出循环了,依旧要判断最后分末尾是否符合要求
        if(lc!=ch[pos]||sum<num[pos]||pos!=cnt)
        {
            f=false;
        }
        if(f)cout<<"YES\n";
        else cout<<"NO\n";

    }
	return 0;
}

C
原题链接:https://codeforces.com/contest/1185/problem/C2
题意:
有n个人考试,每个人都有自己的考试时间ti,总共考试时间为m。现在你可以使某个人直接不通过(耗时为0)或者进行考试(耗时ti)。现在要求你求出要是使第i个人能完成考试,则最少必须使前i-1个人中的多少人直接不通过(第i个人以后的不用考虑)。
题解:
简单版本,直接暴力排序,找耗时小的,使尽可能多的人进行考试。
困难版本,注意到1<=ti<=100,也就是一共仅有100种耗时。所以可以对前i-1个人的耗时进行计数,选择的时候从耗时小到大选择,当该种耗时的人被选完了,在选耗时更大的人。才能使尽可能多的人进行考试。
AC代码:

#include <bits/stdc++.h>
using namespace std;
//why
#define ll long long
int t[2 * 1000 * 105];
int cnt[105];
int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);
    int n, M;
    cin >> n >> M;
    for(int i = 0; i < n; i++)
    {
        cin>>t[i];
        int sum=0;
        int ccnt=0;
        int ls=M-t[i];//计算其他人可以进行考试的时间
        for(int j =1; j<=100;j++)
        {
            sum+=cnt[j]*j;
            ccnt+=cnt[j];
            if(sum>ls)//如果总和大于ls则只选取其中一部分人,否则全选
            {
                sum-=cnt[j]*j;
                ccnt-=cnt[j];
                ccnt+=(ls-sum)/j;
                break;
            }
        }
        cout <<i-ccnt<<" ";
        cnt[t[i]]++;//计数
    }
  return 0;
}

D:
原题链接:https://codeforces.com/contest/1185/problem/D
题意:
给出一个数组,问删除其中的一个数字,能否构成等差数列(可以重新排序)。
题解:
先根据数值大小排序
(1)以第一个和第二个之间的差值为公差,如果后面所有数都满足等差,则删除第一个或者最后一个,若有一个不满足,则输出那一个的位置。
(2)若有多个不满足,则证明可能是公差选取错误,此时选取第三个与第一个之间的差值做为公差(相当于删除掉第二个),若后面的都满足等差,则证明应该删除第二个。
(3)若依旧不可行,那么尝试删除第一个,选取第三个与第二个之间的差值做为公差,若后面的所有数都满足等差,则删除第一个。
(4)若以上的都不可行,则无法构成等差数列,输出-1.

AC代码:

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e6+5;

struct node
{
    int v,p;//v=数值,p=位置
}a[maxn];

bool cmp(node a,node b)
{
    if(a.v==b.v)
        return a.p<b.p;
    return a.v<b.v;
}
int d[maxn];
int main()
{
	ios::sync_with_stdio(false);
    cin.tie(0);
   	cout.tie(0);
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i].v;
        a[i].p=i+1;
    }
    sort(a,a+n,cmp);
    if(n==2)//两个数字,必然构成等差数列,直接删除第一个
    {
        cout<<1;
        return 0;
    }

    int ans=0;
    int cnt=0;
    int d=a[1].v-a[0].v;//以第一个和第二个之间的差值为公差
    for(int i=2;i<n;i++)
    {
        int n=a[0].v+i*d;//等差数列定义,下同
        if(cnt>0)//如果有一个不满足,则假设删去,然后再判断下一个是否满足
            n-=d;
        if(n!=a[i].v)
        {
            cnt++;
            ans=i;
        }
    }
    if(cnt==0)//原数列构成等差数列
    {
        cout<<a[0].p;
        return 0;
    }
    else if(cnt==1)//仅有一个不满足
    {
        cout<<a[ans].p;
        return 0;
    }

    cnt =0;
    d=a[2].v-a[1].v;//以第三个和第二个之间的差值为公差
    for(int i=3;i<n;i++)
    {
        int n=a[1].v+i*d-d;//等差数列定义,下同
        if(n!=a[i].v)
        {
            cnt++;
            ans=i;
        }
    }
    if(cnt==0)//若其后都满足等差
    {
        cout<<a[0].p;
        return 0;
    }

    cnt =0;
    d=a[2].v-a[0].v;以第一个和第三个之间的差值为公差
    for(int i=3;i<n;i++)
    {
        int n=a[0].v+i*d-d;//等差数列定义
        if(n!=a[i].v)
        {
            cnt++;
            ans=i;
        }
    }
    if(cnt==0)//若其后都满足等差
    {
        cout<<a[1].p;
        return 0;
    }
//以上都不可行,则无法构成等差数列
    cout<<-1;
	return 0;
}

E
原题链接:https://codeforces.com/contest/1185/problem/E
题意:
小p爱画蛇,由于各种原因,他只能画宽度为1,长度大于等于1的且不弯曲的蛇,也就是只能水平或者垂直画在一个格子纸上。而且小p用小写字母作为蛇的身体(aaaa、bbb),并且画的顺序是按照字典顺序画的,若后画上的与之前的有重复,则用后画的覆盖之前画的。
现给出一副图,问小p能否按照上述规则在一幅空白的纸上画出来。可以的话,需要输出画法。
题解:
每一种字母蛇仅能画一条,所以如果某个字母蛇的宽度和长度都大于1时,是必然画不出来的。
然后对于字母蛇,可以从后画的到先画的顺序(z->a)判断。
找出每种字母蛇的左上点和右下点,如果该直线内全部都是该字母或者被比他的字母覆盖,则可能画出,每判断完一种字母蛇,将其所覆盖的区域用特殊字符‘+’代替,方便后续的判断。
如果所有的字母都满足,则输出每一种字母的左上点坐标和右下点坐标即可。如果某个字母蛇完全被覆盖,则可以直接输出比他大的字母蛇的左上右下点坐标。
AC代码:

#include <bits/stdc++.h>

using namespace std;
char mp[2005][2005];

struct node
{
    int x,y;//左上
    int xx,yy;//右下
}a[100];

bool vis[100];//判断是否出现过

void p(int n,int m)//中间测试用的
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cout<<mp[i][j]<<" ";
        }
        cout<<endl;
    }
}

int main()
{
	ios::sync_with_stdio(false);
    cin.tie(0);
   	cout.tie(0);
   	int t;
   	cin>>t;
    int n,m;
    while(t--)
    {
        bool f=true;
        cin>>n>>m;
        memset(vis,false,sizeof(vis));//重置数组
        memset(a,0,sizeof(a));
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                cin>>mp[i][j];
                if(mp[i][j]!='.')
                {
                    int d=mp[i][j]-'a';
                    if(d>=26||d<0)f=false;
                    if(!vis[d])//第一次遇到这个字符
                    {
                        a[d].x=a[d].xx=i;
                        a[d].y=a[d].yy=j;
                        vis[d]=true;
                    }
                    else
                    {
                        if(i!=a[d].x&&j!=a[d].y)//如果和之前的不在同一行或者同一列的话,则不可能画出
                        {
                            f=false;
                        }
                        a[d].xx=max(a[d].xx,i);//更新右下点
                        a[d].yy=max(a[d].yy,j);
                    }
                }
            }
        }
        int ans;
        if(!f)
        {
            cout<<"NO\n";
            continue;
        }
        int i;
        for(i=25;i>=0;i--)
        {
            if(vis[i])
                break;
        }
        ans=i+1;//找到画上最大的字母
        for(;i>=0;i--)
        {
            if(!vis[i])continue;//如果被全覆盖,则直接跳过
            int x=a[i].x,y=a[i].y,xx=a[i].xx,yy=a[i].yy;
            if(x==xx)//同行
            {
                for(int j=y;j<=yy;j++)
                {
                    if(mp[x][j]-'a'!=i&&mp[x][j]!='+')//判断是否全为该字符
                    {
                        f=false;
                        break;
                    }
                    mp[x][j]='+';//置为特殊字符
                }
            }
            else if(y==yy)//同列
            {
                for(int j=x;j<=xx;j++)
                {
                    if(mp[j][y]-'a'!=i&&mp[j][y]!='+')//判断是否全为该字符
                    {
                        f=false;
                        break;
                    }
                    mp[j][y]='+';//置为特殊字符
                }
            }
            else
                f=false;
        }
        if(f)
        {
            cout<<"YES\n"<<ans<<"\n";
            for(int i=0;i<ans;i++)
            {
                if(!vis[i])//如果被全覆盖
                {
                    for(int j=1;;j++)找到一个比他的美誉被全覆盖的字母蛇
                    {
                        if(vis[i+j])
                        {
                            cout<<a[i+j].x+1<<" "<<a[i+j].y+1<<" "<<a[i+j].xx+1<<" "<<a[i+j].yy+1<<"\n";
                            break;
                        }
                    }
                }
                else
                    cout<<a[i].x+1<<" "<<a[i].y+1<<" "<<a[i].xx+1<<" "<<a[i].yy+1<<"\n";
            }
        }
        else
            cout<<"NO\n";
    }
	return 0;
}

FG
后续会补上。

欢迎评论!

猜你喜欢

转载自blog.csdn.net/wjl_zyl_1314/article/details/93197888
今日推荐