1622 - Robot 【模拟】

题目大意

传送门

有一个m*n(1<=m,n<=10^5)的网格,每个格子里面都有一个机器人。每次可以发出如下4种命令之一:
NORTH SOUTH EAST WEST,作用是让所有的机器人都往相应的方向移动一格。如果一个机器人在执行某一命令之后走出的网格,那么就会立即炸毁。

给出4种指令的总条数(Cnorth,Csouth,Ceast,Cwest),求出一种指令顺序使得所有的机器人执行的命令条数之和最大。
炸毁的机器人不在执行命令。

样例

input

2 2
1 0 0 0
2 2
1 1 1 1
0 0

output

Case 1: 4
Case 2: 9

解释

思路

思路1:
先调整m和n的大小,保证m < n。
既然m < n,那么每次都对机器人下左右移动的命令。
先左还是先右,取决于向左的命令多还是向右的命令多:

  • 左右的命令分别是5和6,那么先向右,然后左右来5个循环,都用完。
  • 左右的命令分别是5和5,那么先左先右都可以,然后来四个循环,剩下一个命令。
  • 左右的命令分别是5和7,那么先向右,然后左右来5个循环,剩下一个向右的命令。

同理向上还是向下。

但是样例:
1 10
4 7 1 7
答案为67
这个先考虑左右移动,上下移动就不能移动,一旦移动,机器全没了。

所以我们考虑完左右移动之后,不能直接考虑上下,有可能不上下会更好。

在比如样例
5 9
5 10 4 2
答案为671
按照先左右移动算出答案为667,其实答案为671。
所以在 m < n的情况下,不一定先左右就是最优的。
也要考虑先上下。

我Debug中的样例都过了,最后还是wa。。。

代码

#include<cstdio>
#include<map>
#include<queue>
#include<cstring>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stdlib.h>
#include <math.h>
#include <stack>
using namespace std;
#define  LL long long

const LL maxn = 5005;
LL M,N;
LL m,n;
LL Cn,Cs,Ce,Cw;

LL get_ans(LL Cn,LL Cs,LL Ce,LL Cw){
        LL small_1 = min(Ce,Cw);
        LL big_1 = max(Ce,Cw);

        LL small_2 = min(Cn,Cs);
        LL big_2 = max(Cn,Cs);

        //printf("big_1:%d small_1:%d \n",big_1,small_1);
        //printf("big_2:%d small_2:%d \n\n",big_2,small_2);


        LL ans = 0;
        LL sum1 = 0;
        LL sum2 = 0;
        LL sum3 = 0;

        LL sum4 = 0;

        //先左右移动,后上下移动
        if(small_1>0)
        {
            sum1 += m*n;
            big_1 -= 1;
            if(small_1>big_1)
            {
                sum1 += m*(n-1)*(small_1+big_1);
                big_1 = 0;
                small_1 = 0;
            }
            else
            {
                sum1 += m*(n-1)*(min(small_1,big_1)*2);
                LL temp =  min(small_1,big_1);
                big_1 -= temp;
                small_1 -= temp;
            }
            n--;
        }
        //printf("sum1: %d\n\n",sum1);


        //上下移动还是不移动 判断两种:
        //若不移动
        LL tem_m = m;
        LL tem_n = n;
        LL tem_big_1 = max(big_1,small_1);
        LL tem_big_2 = max(big_2,small_2);

        while(tem_m && tem_n && tem_big_1)
        {
            if(tem_m>tem_n && tem_big_2>0)
            {
                swap(tem_m,tem_n);
                swap(tem_big_1,tem_big_2);
            }
            sum4+=tem_m*tem_n;
            tem_big_1--;
            tem_n--;
        }
        while(tem_m && tem_n && tem_big_2)
        {
            sum4 += tem_m*tem_n;
            tem_big_2--;
            tem_m--;
        }
        //printf("sum4: %d\n\n",sum4);


        //若移动
        if(small_2>0)
        {
            sum2 += m*n;
            big_2 -= 1;
            if(small_2>big_2) {
                sum2 += (m-1)*n*(small_2+big_2);
                big_2 = 0;
                small_2 = 0;
            }
            else
            {
                sum2 += (m-1)*n*(min(small_2,big_2)*2);
                LL temp =min(small_2,big_2);
                big_2 -= temp;
                small_2 -= temp;
            }

            m--;
        }
        //printf("sum2 :%d\n\n",sum2);

        big_1 = max(big_1,small_1);
        big_2 = max(big_2,small_2);
        //判断m和n的大小,伺机而动
        while(m&&n&&big_1)
        {
            if(m>n&&big_2>0) //保证每次都是m<=n
            {
                swap(m,n);
                swap(big_1,big_2);
            }
            sum3+=m*n;
            big_1--;
            n--;
        }
        while(m&&n&&big_2)
        {
            sum3+=m*n;
            big_2--;
            m--;
        }
        //printf("sum3 :%d\n",sum3);


        ans = sum1 + max(sum4,sum2+sum3);
}

int main()
{

    LL Casenum=1;
    while(~scanf("%lld%lld",&M,&N))
    {
        if(M==0 && N==0) break;
        scanf("%lld %lld %lld %lld",&Cn,&Cs,&Ce,&Cw);
        m = M;
        n = N;
        LL ans1 = get_ans(Cn,Cs,Ce,Cw);

        m = N;
        n = M;
        LL ans2 = get_ans(Ce,Cw,Cn,Cs);
        //printf("ans1 %d ans2 %d\n\n",ans1,ans2);

        printf("Case %lld: %lld\n",Casenum++,max(ans1,ans2));


    }

}
/*
https://www.udebug.com/UVa/1622
*/

Hit

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值