IOI2010 生活品质

Description:

有一个 n ⋅ m n\cdot m nm的矩阵,每个格子中的数用 1 1 1~ n ⋅ m n\cdot m nm之间不同的数表示,求在一个 h ⋅ w h \cdot w hw的字矩阵中的中位数最小,保证 h ⋅ w h \cdot w hw为奇数。
n , m ≤ 1000 n,m\le 1000 n,m1000

Solution:

  • 因为中位数是固定的一个数,那么我们很容易想到去找一个 h ⋅ w h \cdot w hw的字矩阵中第 K K K大的数最小
  • 因而,我们想到可以二分答案,对于check,我们可以二维前缀和出 ( x 1 , y 1 ) (x1,y1) (x1,y1) ( x 2 , y 2 ) (x2,y2) (x2,y2)中不大于 m i d mid mid的数的个数。
  • 这样复杂度为 Θ ( n m log ⁡ ( n m ) ) \Theta(nm\log (nm)) Θ(nmlog(nm))

Code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
template<class T>inline void Rd(T &x){
	x=0;char c;
	while((c=getchar())<48);
	do x=(x<<1)+(x<<3)+(c^48);
	while((c=getchar())>47);
}

const int N=1002;

int n,m,h,w,Mid;
int A[N][N];

struct p30{
	
	int tmp[N],tot;
	
	void solve(){
		int ans=0x3f3f3f3f;
		REP(x1,1,n-h+1) REP(y1,1,m-w+1){
			tot=0;
			SREP(x2,x1,x1+h) SREP(y2,y1,y1+w) tmp[++tot]=A[x2][y2];
			sort(tmp+1,tmp+1+tot);
			chkmin(ans,tmp[Mid]);
		}
		printf("%d\n",ans);
	}
}p1;

struct p100{

	int sum[N][N];

	int Sum(int x1,int y1,int x2,int y2){
		return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
	}
	
	bool check(int k){
		memset(sum,0,sizeof(sum));
		REP(i,1,n) REP(j,1,m) sum[i][j]=(A[i][j]<=k)+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
		REP(i,1,n-h+1) REP(j,1,m-w+1) if(Sum(i,j,i+h-1,j+w-1)>=Mid) return 1;
		return 0;
	} 
	
	void solve(){
		int L=1,R=n*m,ans=0;
		while(L<=R){
			int mid=(L+R)>>1;
			if(check(mid)) ans=mid,R=mid-1;
			else L=mid+1;
		}
		printf("%d\n",ans);
	}
}p2;

int main(){
//	freopen("quality.in","r",stdin);
//	freopen("quality.out","w",stdout);

	Rd(n),Rd(m),Rd(h),Rd(w);
	Mid=(h*w)/2+1;
	REP(i,1,n) REP(j,1,m) Rd(A[i][j]);

	if(n<=30 && m<=30)p1.solve();
	else p2.solve();
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值