AGC004E - Salvage Robots(dp,思维)

AGC004E - Salvage Robots

Solution

怎么又双叒叕遇到和 N O I P 2020 T 4 NOIP2020T4 NOIP2020T4和那道 C F CF CF题一样的题了啊,惨痛回忆 Q A Q QAQ QAQ

大概就是把问题看成刚开始的点不动,整个网格图动,机器人向上 1 1 1格等于网格整体向下 1 1 1格,左右同理。如果网格某一时刻有一部分在边界外面,就把那些部分切掉,然后把所有经过原点( E E E所在的点)的机器人都收集起来。

因此倘若我们向上、下、左、右分别移动了最多 u , d , l , r u,d,l,r u,d,l,r格,那么现在的网格就是 [ d + 1... n − u , r + 1... m − l ] [d+1...n-u,r+1...m-l] [d+1...nu,r+1...ml]范围内的,然后我们可以选择一个边界位置扩展出去,假设 u + 1 u+1 u+1,那么假设移动到了位置 ( u + 1 , y ) , y ∈ [ l , r ] (u+1,y),y\in[l,r] (u+1,y),y[l,r],显然对于所有 y ∈ [ m a x ( r + 1 , l ) , m i n ( m − l , r ) ] y\in [max(r+1,l),min(m-l,r)] y[max(r+1,l),min(ml,r)],位置 ( u + 1 , y ) (u+1,y) (u+1,y)上的机器人都可以被收集而不影响边界大小。这里要对边界取 m a x / m i n max/min max/min是因为边界外的机器人都超出过边界消失了。

于是我们有了一个 d p dp dp的思路:令 f u , d , l , r f_{u,d,l,r} fu,d,l,r表示向上、下、左、右分别移动了最多 u , d , l , r u,d,l,r u,d,l,r格最多收集的机器人。

每次可以从边界往外扩展一格,然后把那个边界上的机器人都加到新的状态里。预处理横纵方向的机器人个数前缀和即可 O ( 1 ) O(1) O(1)转移。

时间复杂度 O ( n 4 ) O(n^4) O(n4),空间也是 O ( n 4 ) O(n^4) O(n4),空间 256 M B 256MB 256MB,只能开 s h o r t short short

Code

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>

#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second

using namespace std;

template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }

typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;

const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=1e9+7;
const int MAXN=101;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
	int f=1,x=0; char c=getchar();
	while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
	while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
	return x*f;
}
int X,Y;
char st[MAXN];
short f[MAXN][MAXN][MAXN][MAXN],sl[MAXN][MAXN],su[MAXN][MAXN];
signed main()
{
	int n=read(),m=read();
	for (int i=1;i<=n;i++)
	{
		scanf("%s",st+1);
		for (int j=1;j<=m;j++) 
		{
			if (st[j]=='E') X=i,Y=j;
			if (st[j]=='o') sl[i][j]=su[i][j]=1;
		}
	}
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++) sl[i][j]+=sl[i][j-1],su[i][j]+=su[i-1][j];
	for (int u=0;u<X;u++)
		for (int d=0;d<=n-X;d++)
			for (int l=0;l<Y;l++)
				for (int r=0;r<=m-Y;r++) f[u][d][l][r]=-n*m;
	f[0][0][0][0]=0;
	short mx=0;
	for (int u=0;u<X;u++)
		for (int d=0;d<=n-X;d++)
			for (int l=0;l<Y;l++)
				for (int r=0;r<=m-Y;r++)
				{
					if (X-(u+1)>=d+1) upmax(f[u+1][d][l][r],(short)(f[u][d][l][r]+sl[X-(u+1)][min(Y+r,m-l)]-sl[X-(u+1)][max(Y-l-1,r)]));
					if (X+(d+1)<=n-u) upmax(f[u][d+1][l][r],(short)(f[u][d][l][r]+sl[X+(d+1)][min(Y+r,m-l)]-sl[X+(d+1)][max(Y-l-1,r)]));
					if (Y-(l+1)>=r+1) upmax(f[u][d][l+1][r],(short)(f[u][d][l][r]+su[min(X+d,n-u)][Y-(l+1)]-su[max(X-u-1,d)][Y-(l+1)]));
					if (Y+(r+1)<=m-l) upmax(f[u][d][l][r+1],(short)(f[u][d][l][r]+su[min(X+d,n-u)][Y+(r+1)]-su[max(X-u-1,d)][Y+(r+1)]));
					upmax(mx,f[u][d][l][r]);
				}
	printf("%d\n",(int)mx);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值