Codeforces Round #442 (Div. 2)A,B,C,D题解

A - Alex and broken contest
传送门:https://codeforces.com/problemset/problem/877/A
有一天亚历克斯正在创建一个关于他的朋友的比赛,但不小心将其删除了。 幸运的是,所有问题都得到了解决,但现在他需要在其他问题中找到它们。

但是有太多问题需要手动完成。 亚历克斯要求你写一个程序,它将通过它的名字确定问题是否来自这个比赛。

众所周知,问题来自于此次比赛,当且仅当其名称中只包含Alex的朋友姓名之一时。 他朋友的名字是“Danil”,“Olya”,“Slava”,“Ann”和“Nikita”。

名称区分大小写。

输入
唯一的行包含来自小写和大写字母的字符串以及长度不超过100的“_”符号 - 问题的名称。

产量
如果问题来自此比赛则打印“是”,否则打印“否”。

Input
Alex_and_broken_contest
NO
Input
NikitaAndString
YES
Input
Danil_and_Olya
NO

给你字符串,让你找里面有没有这个人朋友的名字,当且仅当有一个朋友名字出现的时候,打印yes。
自然而然想到字符串里面的find()函数,关于find的使用可以看我字符串的专题,有介绍。
直接上ac代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
string s[20]={"Danil","Olya","Slava","Ann","Nikita"};
string c;
int cnt=0,pos;
int main(){
    cin>>c;
    for(int i=0;i<5;i++){
         pos=c.find(s[i]);//在c字符串来找他朋友的名字
            while(pos!=-1){
            //找到了计数++
                cnt++;
                pos=c.find(s[i],pos+1);
                //然后在找到的位置后1位置接着找,看是否还能找到
            }
        }
    if(cnt==1)
        printf("YES\n");
    else
        printf("NO\n");
    return 0;
}

B - Nikita and string
传送门:https://codeforces.com/contest/877/problem/B
One day Nikita found the string containing letters “a” and “b” only.

Nikita thinks that string is beautiful if it can be cut into 3 strings (possibly empty) without changing the order of the letters, where the 1-st and the 3-rd one contain only letters “a” and the 2-nd contains only letters “b”.

Nikita wants to make the string beautiful by removing some (possibly none) of its characters, but without changing their order. What is the maximum length of the string he can get?

Input
The first line contains a non-empty string of length not greater than 5 000 containing only lowercase English letters “a” and “b”.

Output
Print a single integer — the maximum possible size of beautiful string Nikita can get.
大意:
尼基塔认为,如果它可以被切成3个字符串(可能是空的)而不改变字母的顺序,那么字符串是美丽的,其中1-st和3-rd仅包含字母“a”而2-nd仅包含字母 字母“b”。
尼基塔希望通过删除一些(可能没有)其中的字符来使字符串变得漂亮,但不改变它们的顺序。 他能得到的最大弦长是多少?

最初想法想用贪心,找出删除最少的元素,来使得字符串最长。想统计b和a的个数,
但是这道题确实没想到用前缀和后缀来分别统计b前后a的个数,然后双重for循环遍历。
先用前缀后缀数组记录一下每一个'b'前后各还有多少个 'a'(是每一个b哦),再n^2枚举第二部分b的起始和终止位置,使pre[i]+nex[j]+key最大即可 (c为从i到j字符'b'的个数)
还要注意特判全是a的串
Input
abba
Output
4
Input
bab
Output
2
//附上他人借鉴
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define inf 0x3f3f3f3f
using namespace std;
char c[5005];
int pre[5005];
int nex[5005];
int main(){
    cin>>c;
    int len=strlen(c);
    int pos=0;
    memset(pre,0,sizeof(pre));
    memset(nex,0,sizeof(nex));
    for(int i=0;i<len;i++){
        if(c[i]=='b')pre[i]=pos;
        else pos++;
        //记录b前面有多少a,如果遇到b,pos不变,遇到a,pos++
        //pre[2]=1,表示c[2]位置的b前面有1个a
    }
    pos=0;//重新计数
    for(int i=len-1;i>=0;i--){
        if(c[i]=='b')nex[i]=pos;
        else pos++;
        //b后有多少a
    }
    int max=-inf;
    for(int i=0;i<len;i++){
        int key=0;
        for(int j=i;j<len;j++){
            if(c[j]=='a')continue;
            else if(c[j]=='b')key++;
            //用j来枚举b的起始和终止位置
            if((pre[i]+nex[j]+key)>max)
                max=pre[i]+nex[j]+key;
            //b前面的a加上后面的a加上b的长度遍历,选出最大的
        }
        //特判,字符串全是a,没有进入下面比较,max仍为初值负无穷大
        if(max==-inf)
            max=len;
    }
     printf("%d\n",max);
    return 0;
}
//例如:abbbba,b出现了4次,所以key加了4次
//此时,pre[0]=0,pre[1]=1,pre[2]=1,pre[3]=1,pre[4]=1;
//说明前四个b前只有一个a
//同样的,前四个b后只有一个a
//nex[5]=0,nex[4]=1,nex[3]=1,nex[2]=1,nex[1]=1;
//但要注意j的起始应该从i开始,而不是从0开始,为什么呢?
//试想i=1,j=0的情况,会怎么样呢?是不是会多算了?
//循环变量要想清楚,在设置。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int b[5005];
int c[5005];
int main(){
    char a[5001];
    cin>>a+1;
    int t=strlen(a+1);
    for(int i=1;i<=t;i++){
        b[i]=b[i-1]+(a[i]=='a');//前i个a的个数
        c[i]=c[i-1]+(a[i]=='b');//前i个b的个数
    }
    int ans=0;
    for(int i=0;i<=t;i++){//为什么不从1开始,因为aba有空串情况
        for(int j=i;j<=t;j++){
            ans=max(ans,b[i]+c[j]-c[i]+b[t]-b[j]);//(前i个a的个数)+(i到j的b的个数)+(j到t的a的个数)
        }
    }
    cout<<ans;
    return 0;
}

C - Slava and tanks
传送门:https://codeforces.com/problemset/problem/877/C
Slava plays his favorite game “Peace Lightning”. Now he is flying a bomber on a very specific map.

Formally, map is a checkered field of size 1 × n, the cells of which are numbered from 1 to n, in each cell there can be one or several tanks. Slava doesn’t know the number of tanks and their positions, because he flies very high, but he can drop a bomb in any cell. All tanks in this cell will be damaged.

If a tank takes damage for the first time, it instantly moves to one of the neighboring cells (a tank in the cell n can only move to the cell n - 1, a tank in the cell 1 can only move to the cell 2). If a tank takes damage for the second time, it’s counted as destroyed and never moves again. The tanks move only when they are damaged for the first time, they do not move by themselves.

Help Slava to destroy all tanks using as few bombs as possible.

Input
The first line contains a single integer n (2 ≤ n ≤ 100 000) — the size of the map.

Output
In the first line print m — the minimum number of bombs Slava needs to destroy all tanks.

In the second line print m integers k1, k2, …, km. The number ki means that the i-th bomb should be dropped at the cell ki.

If there are multiple answers, you can print any of them.
形式上,地图是尺寸为1×n的格子场,其单元格从1到n编号,在每个单元格中可以有一个或多个坦克。斯拉瓦不知道坦克的数量和他们的位置,因为他飞得很高,但是他可以在任何一个牢房里投下炸弹。此电池中的所有储罐都将损坏。

如果坦克第一次受到伤害,它会立即移动到其中一个相邻的单元格(单元格中的坦克n只能移动到单元格n - 1,单元格1中的坦克只能移动到单元格2) 。如果坦克第二次受到伤害,它将被视为已被摧毁并且永远不会再次移动。坦克只有在第一次受损时才会移动,它们不会自行移动。

使用尽可能少的炸弹帮助斯拉瓦摧毁所有坦克。

用贪心做吧。有种模拟的感觉
尽可能少的炸弹,说明炸弹的范围要够大,我最先开始想的是先炸中间的,中间的会往两边跑,炸完中间再炸两边。
但是这样没有做到优化。
举个例子:n为5,怎么炸?
我们先炸偶数位,会出现什么?先炸22里面的坦克会受伤一次,然后往13跑。
再炸44里面的坦克会受伤一次,往35跑。
再炸11里面的坦克会受伤一次,并且从2跑到1的坦克就会阵亡。1的坦克会跑到233里面的坦克会受伤一次,并且从24跑到3的坦克会阵亡。3的坦克会跑到2455里面的坦克会受伤一次,并且从4跑到5的坦克会阵亡。5的坦克会跑到4
现在哪里还有坦克呢?显然易见,只有2,和4剩坦克了,只需2次全部炸完。
Input
2
Output
3
2 1 2 
Input
3
Output
4
2 1 3 2 
#include<iostream>
#include<cstdio>
using namespace std;
int n;
int main(){
    while(~scanf("%d",&n)){
        printf("%d\n",n+n/2);//遍历一遍的次数+偶数的次数
        for(int i=2;i<=n;i+=2)
            printf("%d ",i);
        for(int i=1;i<=n;i+=2)
            printf("%d ",i);
        for(int i=2;i<=n;i+=2){
            if(i!=n)
            printf("%d ",i);
            else
                printf("%d\n",i);
        }
    }
    return 0;
}

Olya and Energy Drinks
传送门:https://codeforces.com/problemset/problem/877/D
Olya loves energy drinks. She loves them so much that her room is full of empty cans from energy drinks.

Formally, her room can be represented as a field of n × m cells, each cell of which is empty or littered with cans.

Olya drank a lot of energy drink, so now she can run k meters per second. Each second she chooses one of the four directions (up, down, left or right) and runs from 1 to k meters in this direction. Of course, she can only run through empty cells.

Now Olya needs to get from cell (x1, y1) to cell (x2, y2). How many seconds will it take her if she moves optimally?

It’s guaranteed that cells (x1, y1) and (x2, y2) are empty. These cells can coincide.

Input
The first line contains three integers n, m and k (1 ≤ n, m, k ≤ 1000) — the sizes of the room and Olya’s speed.

Then n lines follow containing m characters each, the i-th of them contains on j-th position “#”, if the cell (i, j) is littered with cans, and “.” otherwise.

The last line contains four integers x1, y1, x2, y2 (1 ≤ x1, x2 ≤ n, 1 ≤ y1, y2 ≤ m) — the coordinates of the first and the last cells.

Output
Print a single integer — the minimum time it will take Olya to get from (x1, y1) to (x2, y2).

If it’s impossible to get from (x1, y1) to (x2, y2), print -1.

Input
3 4 4
....
###.
....
1 1 3 1
Output
3
Input
3 4 1
....
###.
....
1 1 3 1
Output
8
Input
2 2 1
.#
#.
1 1 2 2
Output
-1

Olya喜欢能量饮料。她非常爱他们,她的房间里充满了能量饮料的空罐头。

在形式上,她的房间可以表示为n×m个细胞的区域,每个细胞都是空的或散落着罐头。

Olya喝了很多能量饮料,所以现在她每秒可以跑k米。每一秒,她选择四个方向中的一个(上,下,左或右),并沿此方向从1到k米。当然,她只能穿过空单元格。

现在Olya需要从单元格(x1,y1)到单元格(x2,y2)。如果她最佳地移动,她会花多少秒?

保证单元格(x1,y1)和(x2,y2)为空。这些细胞可以重合。

每秒可以朝向一个方向走(1~k)步,问从起点走到终点最少需要多少秒。
bfs剪枝,该好好刷刷搜索专题了,剪枝就是先排除一些不可能的情况,使情况更加简单。
网上大佬用二进制枚举状态压缩,但是我不太会,可能运行慢一点,不过也能a
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
using namespace std;
int n,m,k;
int a,b,c,d;
char maze[1005][1005];
bool vis[1005][1005];
int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
struct node{
    int x,y,step;
}st,now;
bool check(int x,int y){
//判断它的下一步在不在房间里
    if(x<1||x>n||y<1||y>m)
        return false;
    return true;
}
int bfs(){
    if(a==c&&b==d){
    //特判自己走到自己
        return 0;
    }
    memset(vis,false,sizeof(vis));
    st.x=a;//把起点赋值给st
    st.y=b;
    st.step=0;
    queue<node>q;
    q.push(st);//放进队列
    vis[st.x][st.y]=true;//标记已走过
    while(!q.empty()){
        st=q.front();
        q.pop();
        int x,y;
        x=st.x;//这个点不能漏,漏了会wa
        y=st.y;
        now.step=st.step;
        for(int i=0;i<4;i++){
            for(int j=1;j<=k;j++){
                now.x=x+dir[i][0]*j;
                now.y=y+dir[i][1]*j;
                if(now.x==c&&now.y==d)
                    return now.step+1;
                if(!check(now.x,now.y)||maze[now.x][now.y]=='#')
                    break;
                if(vis[now.x][now.y]==false){
                    vis[now.x][now.y]=true;
                    st.x=now.x;
                    st.y=now.y;
                    st.step=now.step+1;
                    q.push(st);
                }
            }
        }
    }
    return -1;
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++)
            cin>>maze[i][j];
    }
    scanf("%d%d%d%d",&a,&b,&c,&d);
    printf("%d\n",bfs());
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值