[CODE FESTIVAL 2017 Final]H

题面在这里

吐槽:

真是一道不错的联赛题目,根据出题人来说,这种略有思维难度神仙题目放到校内NOIP集训来做还是挺合适的。

思路:

首先考虑冰块如何消掉,最开始看到的就是从某一个角开始一直消。
然后一个骗分的方法就是枚举四个角,把角上的那个矩形内的厚冰块全部消掉。
但是实际情况可能是这样的:在某一个矩形之内划了一个十字型之后两块相对的地方都没有厚冰块,然后另外两块开始变得独立起来。换一句话说,这两块独立的矩形的角可以像原来的大冰块一样开始消。
于是我们可以枚举包含的P的所有矩形并且计算出它独立的最小代价,然后枚举四个角把它消掉,取最小值。
考虑如何计算一个矩形独立的最小值,设(dp_{i,j,k,l})表示这个矩形的两个角,然后在矩形中央枚举一个十字形的叉叉,直接转移即可。
时间复杂度要考虑常数,即(O(frac{(nm)^3}{8}))

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define MREP(i,x) for(int i=beg[x],v;v=to[i],i;i=las[i])
#define debug(x) cout<<#x<<"="<<x<<endl
#define fi first
#define se second
#define mk make_pair
#define pb push_back
#define y1 asdasd
typedef long long ll;

using namespace std;

void File(){
	freopen("haner.in","r",stdin);
	freopen("haner.out","w",stdout);
}

template<typename T>void read(T &_){
	T __=0,mul=1; char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')mul=-1;
		ch=getchar();
	}
	while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
	_=__*mul;
}

const int maxn=40+10;
const int inf=0x3f3f3f3f;
int n,m,px,py,dp[maxn][maxn][maxn][maxn],sum[maxn][maxn],ans=inf;
char s[maxn][maxn];

int S(int x1,int y1,int x2,int y2){
	return sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];
}

template<typename T>void chkmin(T &_,T __){_=_<__ ? _ : __;}

int main(){
	File();
	read(n); read(m);
	REP(i,1,n)scanf("%s",s[i]+1);
	REP(i,1,n){
		REP(j,1,m){
			if(s[i][j]=='P'){
				px=i; py=j; s[i][j]='+';
			}
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(s[i][j]=='#');
			//cout<<sum[i][j]<<" ";
		}
		//cout<<endl;
	}
	memset(dp,63,sizeof(dp));
	dp[1][1][n][m]=0;//代表将(1,1,n,m)这个矩形独立的最小代价为0。
	REP(x1,1,n)REP(y1,1,m)
		DREP(x2,n,x1)DREP(y2,m,y1){
			if(x1<=px && x2>=px && y1<=py && y2>=py){
				int w=dp[x1][y1][x2][y2];
				REP(x,x1,x2)REP(y,y1,y2){
					int cost1=S(x1,y1,x,y)+S(x+1,y+1,x2,y2);
					int cost2=S(x1,y+1,x,y2)+S(x+1,y1,x2,y);
					chkmin(dp[x1][y+1][x][y2],cost1+w);
					chkmin(dp[x+1][y1][x2][y],cost1+w);
					chkmin(dp[x1][y1][x][y],cost2+w);
					chkmin(dp[x+1][y+1][x2][y2],cost2+w);
				}
				//cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<" "<<w<<endl;
				chkmin(ans,w+S(x1,y1,px,py));
				chkmin(ans,w+S(px,py,x2,y2));
				chkmin(ans,w+S(px,y1,x2,py));
				chkmin(ans,w+S(x1,py,px,y2));
			}
		}
	printf("%d
",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/ylsoi/p/9911590.html