传送门:http://agc004.contest.atcoder.jp/tasks/agc004_e
大概翻译:
在一个H*W 的网格中有若干个机器人和一个出口,其余是空地。每次你可以让所有机器人往某个方向移动一步。当机器人移动到出口时候会被取出,当机器人移出网格时会爆炸。求你最多取出多少机器人。
H,W<=100
首先可以看出来取走一个机器人的代价是舍弃反方向的一些行列,所以可以发现能取走的机器人区域总体而言还是挺“方”的。
总而言之,做法就是枚举一个状态,f[i][j][k][p]表示拿走了的机器人的坐标(不一定要对应到实在的机器人,即可以对应取走空地)
然后枚举向上下左右拓展一行(列)分别能拿走多长的区间
tips:在纸上认真算好转移各种边界之类的
以上应该很好想到,所以这题的瓶颈不在于此,而是那个空间的问题……
同学:状态数最多50^4
我:那直接映射一个下标做
———–(各种迷+训练打乱了写题计划)———–
我:这东西写起来真恶心
同学:……(沉默)
同学:其实100^4个short不会炸空间……
我:(O__O “)…
#include<stdio.h>
#include<iostream>
#include<algorithm>
#define N 105
using namespace std;
short line[N][N],list[N][N],ans[N][N][N][N],n,m,op,sx,sy;
char s[N][N];
int main()
{
cin>>n>>m;
for (short i=1;i<=n;i++) scanf("%s",s[i]+1);
for (short i=1;i<=n;i++) for (short j=1;j<=m;j++)
{
line[i][j]=line[i][j-1]+(s[i][j]=='o');
list[i][j]=list[i-1][j]+(s[i][j]=='o');
if (s[i][j]=='E') sx=i,sy=j;
}
for (short i=sx;i;i--) for (short j=sy;j;j--)
for (short k=sx;k<=n;k++) for (short p=sy;p<=m;p++)
{
if (1<i && k+1<sx+i) op=max(op,ans[i-1][j][k][p]=max((int)ans[i-1][j][k][p],ans[i][j][k][p]+line[i-1][min((int)p,m-sy+j)]-line[i-1][max(j-1,p-sy)]));
if (k<n && sx+k<n+i) op=max(op,ans[i][j][k+1][p]=max((int)ans[i][j][k+1][p],ans[i][j][k][p]+line[k+1][min((int)p,m-sy+j)]-line[k+1][max(j-1,p-sy)]));
if (1<j && p+1<sy+j) op=max(op,ans[i][j-1][k][p]=max((int)ans[i][j-1][k][p],ans[i][j][k][p]+list[min((int)k,n-sx+i)][j-1]-list[max(i-1,k-sx)][j-1]));
if (p<m && sy+p<m+j) op=max(op,ans[i][j][k][p+1]=max((int)ans[i][j][k][p+1],ans[i][j][k][p]+list[min((int)k,n-sx+i)][p+1]-list[max(i-1,k-sx)][p+1]));
}
cout<<op;
}