【2020.10.29 牛客 普及组 模拟赛6】T3 小球下落

102 篇文章 1 订阅
16 篇文章 0 订阅

题目描述
有一块大小为n行2列的板子,每个位置可能是一个小球,用 ′ o ′ 'o' o表示,可能是障碍物,用 ′ x ′ 'x' x表示,也可能空无一物,用 ′ . ′ '.' .来表示。

每个小球可以向左向右或者向下移动,但是不能向上移动,或者和某个小球重叠,也不能越出板子。

每个小球向下移动一个单位,牛牛可以获得一分。

牛牛想知道对于某个开始状态,能得到的最大分数是多少。


输入描述:
第一行输入一个整数n,表示板子的行数。

随后n行,每行一个长度为2的字符串,如题意所示。

设有k个小球。

对于 20 20 20%的数据有 n ≤ 3 n≤3 n3

另有 20 20 20%的数据 k ≤ 10 k≤10 k10

对于 60 60 60%的数据有n 1000 n ≤ 1000 1000n≤1000 1000n1000

对于 100 100 100%的数据有 1 ≤ n ≤ 300000 1≤n≤300000 1n300000

输出描述:
一行一个整数表示答案。


示例1
输入
10
oo
.o
.x
x.

oo
.o
x.

x.

输出
12


说明

最终结果为:

oo
ox
x.



x.
oo
xo


解题思路

当时打了个暴搜,结果测的大样例错了,没时间修改了,不抱希望的交了上去,结果尽然骗到了40分!

正解:
首先核心思想是贪心。反向输入图形,把第行当作第行,现在的目标就是尽可能的去让球去填满上面的空。但是,有三种情况是会封死路的:
在这里插入图片描述
看看代码,然后读完下面的解释你就懂了。

  • F数组下标是递增的,代表目前除了x的个数; F数组的值代表这个不是x的字符是第几行的。
    顺着下来,上去的球就也相当于点了。
  • p就是下标.
    if(a[i][1]!=1)f[p++]=i; if(a[i][2]!=1)f[p++]=i;
  • t为全部空位(包括点和已经上去的球)已被球占用了的个数,也同样作为的下标。
    if(a[i][1]==2)ans+=f[t++]-i; if(a[i][2]==2)ans+=f[t++]-i;
    ans加上当前行减去目前存在空位最上面的行,t继续自增.
  • 最后,就是当出现三种拦路的情况,直接让 p , t p,t p,t 都清即可。相当于就是开辟了个新的分区,啥都清了。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
long long n,ans,p,t,a[400000][3],f[1000000];
char c;
int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=2; j++)
        {
            cin>>c;
            if(c=='o')
                a[i][j]=2;
            if(c=='x')
                a[i][j]=1;
            if(c=='.')
                a[i][j]=0;
        }
    }
    for(int i=n; i>0; i--)
    {
        if(a[i][1]!=1)f[p++]=i;
        if(a[i][2]!=1)f[p++]=i;
        if(a[i][1]==2)ans+=f[t++]-i;
        if(a[i][2]==2)ans+=f[t++]-i;
        if((a[i][1]==1&&a[i][2]==1)||(a[i][1]==1&&a[i-1][2]==1)||(a[i-1][1]==1&&a[i][2]==1)) 
			p=t=0;
    }
    printf("%lld",ans);
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值