题目大意
有一个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
*/