【HDU6639 Faraway】绝对值暴力余数

传送门

题意

给n个式子的xi,yi,ki,ti,求满足这n个式子的解{x,y}的个数。
解的范围为0~m。
式子形如: ( ∣ x i − x ∣ + ∣ y i − y ∣ ) m o d k i = t i . (|x_i−x|+|y_i−y|)mod k_i=t_i. (xix+yiy)modki=ti.
n &lt; = 10 , 2 &lt; = k i &lt; = 5 n&lt;=10,2&lt;=k_i&lt;=5 n<=102<=ki<=5

思路

有绝对值,首先考虑去绝对值。
把平面分成n2个区域,在每个区域内,绝对值的影响可被忽略 。
即式子变为 ( x i + y i − x − y ) m o d k i = t i . (x_i+y_i−x−y)mod k_i=t_i. (xi+yixy)modki=ti.
k一共只有2、3、4、5四种取值,也就是对于每组解中的x、y,最多只有 l c m ( 2 , 3 , 4 , 5 ) = 60 lcm(2,3,4,5)=60 lcm(2,3,4,5)=60种对k取余的结果。
故只需枚举x、y对60的余数:0~59,然后验证,若这个余数可以,就计算这个余数下的答案数量。

标程

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=15,K=60;
int Case,n,m,x,y,i,j,ca,cb,a[N],b[N];long long ans;
struct E{
	int x,y,k,t;
}e[N];
inline int abs(int x){
	return x>0?x:-x;
}
inline bool check(int x,int y){
	for(int i = 0; i < n;i ++)
		if((abs(x-e[i].x) + abs(y-e[i].y)) % e[i].k!=e[i].t)
			return 0;
	return 1;
}
inline int cal(int l,int r){
	r -= l+1;
	if(r < 0)return 0;
	return r/K+1;
}
int main(){
	scanf("%d",&Case);
	while(Case--){
		scanf("%d%d",&n,&m);
		ca = 1;
		cb = 1;
		a[ca] = b[cb] = m+1;
		//保存下来每个方程  
		for(i = 0; i < n; i ++){
			scanf("%d%d%d%d", &e[i].x, &e[i].y, &e[i].k, &e[i].t);
			a[++ca] = e[i].x;
			b[++cb] = e[i].y;
		}
		//对于每个区域求解 
		sort(a+1, a+ca+1);
		sort(b+1, b+cb+1);
		ans = 0;
		//分区域,使绝对值不影响答案个数 
		for(i = 0; i < ca; i ++) 
			if(a[i] < a[i+1])//防止区域重复
				for(j = 0; j < cb; j ++)
					if(b[j] < b[j+1])//防止区域重复 
						for(x = 0; x < K; x ++)  //枚举目标坐标x、y的余数 
							for(y = 0; y < K; y ++) 
								if(check(a[i]+x,b[j]+y))//如果目标满足题目的式子们(+60不影响取模结果) 
									ans += 1LL * cal(a[i]+x,a[i+1]) * cal(b[j]+y,b[j+1]);// 区域里有多少这个余数的答案 
		printf("%lld\n",ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值