BZOJ 1169: [Baltic2008]Grid

一个矩阵,可以横着切S刀,竖着切R刀,求小矩阵和最大的最小是多少。
二分答案,dfs出竖着切的,横着贪心check。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 25;
ll a[maxn][maxn];
int n,m,R,S;

template<typename T> inline void read(T &x){
x=0;T f=1;char ch;do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');do x=x*10+ch-'0',ch=getchar();while(ch<='9'&&ch>='0');x*=f;
}

template<typename A,typename B> inline void read(A&x,B&y){read(x);read(y);}
template<typename A,typename B,typename C> inline void read(A&x,B&y,C&z){read(x);read(y);read(z);}
template<typename A,typename B,typename C,typename D> inline void read(A&x,B&y,C&z,D&w){read(x);read(y);read(z);read(w);}

bool ok;

int dl[maxn];
ll mid;
ll bs[maxn];

bool isok(){
	//if(dl[0]==2&&dl[1]==4) cout<<"mid"<<mid<<endl;
	dl[R]=n;
	memset(bs,0,sizeof bs);
	//int bef=0;
	int cnt=0;
	for(int i=1;i<=m;i++){
		bool can=1;
		for(int j=0;j<=R;j++){
			if(j==0&&bs[j]+a[dl[j]][i]-a[dl[j]][i-1]>mid) can=0;
			else if(bs[j]+a[dl[j]][i]-a[dl[j]][i-1]-(a[dl[j-1]][i]-a[dl[j-1]][i-1])>mid)
				can=0;
		}
		if(!can){
			cnt++;
			for(int j=0;j<=R;j++){
				bs[j]=0;
			}
		}
		for(int j=0;j<=R;j++){
			if(j==0) bs[j]+=a[dl[j]][i]-a[dl[j]][i-1];
			else bs[j]+=a[dl[j]][i]-a[dl[j]][i-1]-(a[dl[j-1]][i]-a[dl[j-1]][i-1]);
		}
		for(int j=0;j<=R;j++)
			if(bs[j]>mid) return 0;
	}
	return cnt<=S;
}

void dfs(int now,int dep){
	if(ok) return;
	if(dep==R){
		if(isok()) ok=1;
		return;
	}
	for(int i=now;i<n;i++){
		dl[dep]=i;
		dfs(i+1,dep+1);
	}
}

bool check(ll mid){
	ok=0;
	dfs(1,0);
	if(ok) return 1;
	return 0;
}

int main(){
	//freopen("in.txt","r",stdin);
	read(n,m,R,S);
	R=min(R,n-1);S=min(S,m-1);
	ll l=0,r=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			read(a[i][j]),r+=a[i][j];
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			a[i][j]=a[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1];
	//for(int i=1;i<=n;i++)
	//	for(int j=1;j<=m;j++)
	//		printf("%d%c",(int)a[i][j]," 
"[j==m]);
	ll res=-1;
	//cout<<check(mid=31)<<endl;
	//l=r=130;
	while(l<=r){
		mid=(l+r)/2;
		if(check(mid))
			r=(res=mid)-1;
		else l=mid+1;
	}
	cout<<res;
	return 0;
}
原文地址:https://www.cnblogs.com/foreignbill/p/7921148.html