LA 3695 Distant Galaxy

题目:Distant Galaxy


思路:

先离散化。

令 lft [i] [j] 为 第i行前j列点的个数和, sum [i] [j] 为第j列前i行点的个数和。

枚举上下边界,记作 x=i、x=j 。

令 on [k] 为 以 (i,k) (j,k) 为端点的线段当的点数和(不包括端点),计算方法是 on[k]=sum[j-1][k]-sum[i][k]。

假设 s(i,j) 为以 (i,x) (j,y) (i,y) (j,x) 为顶点的矩形边上的点数( i<j , x<y ),可知:

s(i,j)max 
= (on(x)+on(y)+lft(i,y)-lft(i,x-1)+lft(j,y)-lft(j,x-1))max 
= (on(y)+lft(i,y)+lft(j,y))max - (lft(i,x-1)+lft(j,x-1)-on(x))min 
为了方便,令 a[y]=on[y]+lft[i][y]+lft[j][y] , b[x]=lft[i][x-1]+lft[j][x-1]-on[x] ,问题就转化成了求两个整数 x,y (x<y),使得a[y]-b[x]的值最大。

此时只需从小到大枚举y,在每枚举到一个y时,顺便计算出一个小于y的使得b[x]最小的x就可以了。


注意:

1、坐标有负数。

2、当所有点在同一行或同一列时,要特殊判断。

3、on的计算,这里不能包括上下的端点。


代码:

#include<bits/stdc++.h>
using namespace std;

#define maxn 100

struct Point {
	int x,y;
	Point(int xx=0,int yy=0) {
		x=xx,y=yy;
	}
};

int n;

int cntr,cntc;	//不同的横坐标的个数,不同的纵坐标的个数。即离散化后的图的长和宽
bool g[maxn+5][maxn+5];

int lft[maxn+5][maxn+5];	//第i行前j列点的个数和
int sum[maxn+5][maxn+5];	//第j列前i行点的个数和

void init() {
	cntr=cntc=0;
	memset(g,0,sizeof(g));
	memset(lft,0,sizeof(lft));
	memset(sum,0,sizeof(sum));
}

void readin() {
	Point a[maxn+5];
	int row[maxn+5],col[maxn+5];
	for(int i=1; i<=n; i++) {
		scanf("%d%d",&a[i].x,&a[i].y);
		row[i]=a[i].x,col[i]=a[i].y;
	}

	//离散化
	sort(row+1,row+n+1),sort(col+1,col+n+1);

	map<int,int> mpr,mpc;
	for(int i=1; i<=n; i++) {
		if(!mpr.count(row[i])) cntr++,mpr[row[i]]=cntr;
	}
	for(int i=1; i<=n; i++) {
		if(!mpc.count(col[i])) cntc++,mpc[col[i]]=cntc;
	}

	for(int i=1; i<=n; i++) {
		a[i]=Point(mpr[a[i].x],mpc[a[i].y]);
		g[a[i].x][a[i].y]=true;
	}
}

void make_lft() {
	for(int i=1; i<=cntr; i++) {
		for(int j=1; j<=cntc; j++) {
			lft[i][j]=lft[i][j-1];
			if(g[i][j]) lft[i][j]++;
		}
	}
}

void make_sum() {
	for(int j=1; j<=cntc; j++) {
		for(int i=1; i<=cntr; i++) {
			sum[i][j]=sum[i-1][j];
			if(g[i][j]) sum[i][j]++;
		}
	}
}

void make_on(int x,int y,int *on) {
	for(int i=1; i<=cntc; i++) {
		on[i]=sum[y-1][i]-sum[x][i];
	}
}

void make_a(int i,int j,int *on,int *a) {
	for(int y=1; y<=cntc; y++) {
		a[y]=on[y]+lft[i][y]+lft[j][y];
	}
}

void make_b(int i,int j,int *on,int *b) {
	for(int x=1; x<=cntc; x++) {
		b[x]=lft[i][x-1]+lft[j][x-1]-on[x];
	}
}

int main() {

	int T=0;
	while(~scanf("%d",&n)&&n) {
		init();
		readin();
		make_lft();
		make_sum();
		
		int ans=0;
		if(cntr==1||cntc==1) ans=n;
		else for(int i=1; i<=cntr; i++) {	//枚举上下边界
				for(int j=i+1; j<=cntr; j++) {
					int on[maxn+5]= {0};
					make_on(i,j,on);
					
					int a[maxn+5],b[maxn+5];	//a[y]=on[y]+lft[i][y]+lft[j][y],b[x]=lft[i][x-1]+lft[j][x-1]-on[x]
					make_a(i,j,on,a),make_b(i,j,on,b);

					int x=1;
					for(int y=2; y<=cntc; y++) {
						ans=max(a[y]-b[x],ans);
						if(b[y]<b[x]) x=y;
					}
				}
			}
		printf("Case %d: %d\n",++T,ans);
	}

	return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值