hiho 编程之美2015资格赛(基站选址-绝对值方程分段)[WA]

题目3 : 基站选址

时间限制: 2000ms
单点时限: 1000ms
内存限制: 256MB

描述

需要在一个N × M的网格中建立一个通讯基站,通讯基站仅必须建立在格点上。

网格中有A个用户,每个用户的通讯代价是用户到基站欧几里得距离的平方。

网格中还有B个通讯公司,维护基站的代价是基站到最近的一个通讯公司的路程(路程定义为曼哈顿距离)。

在网格中建立基站的总代价是用户通讯代价的总和加上维护基站的代价,最小总代价。

输入

第一行为一个整数T,表示数据组数。

每组数据第一行为四个整数:N, M, A, B。

接下来的A+B行每行两个整数x, y,代表一个坐标,前A行表示各用户的坐标,后B行表示各通讯公司的坐标。

输出

对于每组数据输出一行"Case #X: Y",X代表数据编号(从1开始),Y代表所求最小代价。

数据范围

1 ≤ T ≤ 20

1 ≤ x ≤ N

1 ≤ y ≤ M

1 ≤ B ≤ 100

小数据

1 ≤ N, M ≤ 100

1 ≤ A ≤ 100

大数据

1 ≤ N, M ≤ 107

1 ≤ A ≤ 1000

样例输入
2
3 3 4 1
1 2
2 1
2 3
3 2
2 2
4 4 4 2
1 2
2 4
3 1
4 3
1 4
1 3
样例输出
Case #1: 4
Case #2: 13

x,y可以单独考虑,∑(X-xi)^2+|x-a| 在[1,n]整数范围内最小值,解方程即可


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (10000000+10)
#define MAXA (1000+10)
typedef long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int T;
int n,m,A,B;
ll _x[MAXN],_y[MAXN];

ll a2[MAXN],b2[MAXN];
ll f(ll a,ll b,ll c,ll x){return a*x*x+b*x+c;}
ll calc(int i,ll _x[],ll a2[],ll n)
{
	
	ll a=A,b=0,c=0;
	For(i,A) b+=-2*_x[i],c+=_x[i]*_x[i];
	b+=1;c-=a2[i];		
	double x= (double)((double)(-b)/double(2*a));
	ll X1=floor(x),X2=ceil(x);
	
	ll ans1 = f(a,b,c,a2[i]);
	if (0<=X1&&X1<=n&&X1>a2[i]) ans1=min(ans1,f(a,b,c,X1));
	if (0<=X2&&X2<=n&&X2>a2[i]) ans1=min(ans1,f(a,b,c,X2));
	if (0>a2[i]) ans1=min(ans1,f(a,b,c,0));
	if (n>a2[i]) ans1=min(ans1,f(a,b,c,n));
	
	a=A,b=0,c=0;
	For(i,A) b+=-2*_x[i],c+=_x[i]*_x[i];
	b-=1;c+=a2[i];		
	x= (double)((double)(-b)/double(2*a));
	X1=floor(x),X2=ceil(x);
	
	if (0<=X1&&X1<=n&&X1<a2[i]) ans1=min(ans1,f(a,b,c,X1));
	if (0<=X2&&X2<=n&&X2<a2[i]) ans1=min(ans1,f(a,b,c,X2));
	if (0<a2[i]) ans1=min(ans1,f(a,b,c,0));
	if (n<a2[i]) ans1=min(ans1,f(a,b,c,n));
	
	
	
	return ans1;
	
/*	a=n,b=0,c=0;
	For(i,n) b+=-2*_y[i],c+=_y[i]*_y[i];
	ll Y= floor((double)(-2*a)/double(b));
	return ans;	
*/
}
int main()
{
//	freopen("base.in","r",stdin);
	
	scanf("%d",&T);
	For(kcase,T)
	{
		scanf("%d%d%d%d",&n,&m,&A,&B);
		
		For(i,A)
		{
			scanf("%lld%lld",&_x[i],&_y[i]);
		}
		
		
		int ans=-1;
		For(i,B)
		{
			scanf("%lld%lld",&a2[i],&b2[i]);
			int p=calc(i,_x,a2,n)+calc(i,_y,b2,m);
			if (ans==-1||p<ans) ans=p;
		}
		
		
		
		printf("Case #%d: %lld\n",kcase,ans);
	}
	 
	
	
	
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值