2019 Multi-University Training Contest 6 :Faraway (1006)

题链接

Problem Description

n soldiers are dispatched to somewhere in Byteland. These soldiers are going to set off now, but the target location is not so clear.

Assume the target location is at (xe,ye), it is clear that xe,ye are both non-negative integers within [0,m]. For the i-th soldier, the only thing he knows is that (|xi−xe|+|yi−ye|)modki=ti.

To find the correct target location, these soldiers are working on the information they have now. Please write a program to figure out the number of possible target locations

Input

The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.

In each test case, there are two integers n,m(1≤n≤10,1≤m≤109) in the first line, denoting the number of soldiers and the upper bound of xe,ye.

For the next n lines, each line contains four integers xi,yi,ki,ti(0≤xi,yi≤m,2≤ki≤5,0≤ti<ki), denoting what each soldier knows.

Output

For each test case, print a single line containing an integer, denoting the number of possible target locations.

 

Sample Input

2 2 5 1 2 4 2 3 1 2 1 2 5 1 2 4 2 1 2 4 3

Sample Outpu

10 0

Source

2019 Multi-University Training Contest 6

题意:平面上有n个点,给出每个点的xi, yi, ki, ti,问在 [0, m] 区域内,有多少个点 ( xe, ye) 对每一个i点,满足  ( |xi−xe| + |yi−ye| ) % ki = ti.

题解:比赛时知道找到一个特解,然后每次移动一个最小公倍数,但是没想到把一个点分为四个区域,从而去掉等式的绝对值,简直菜得ya批。

把每个点分为四个区域后,得到图形应该有小于(n + 1)^2个区域(加上0和m边界),然后再暴力枚举每一个区域,计算每个区域内符合条件的点数。

怎么计算每个区域内符合条件的点呢?

因为在每个区域计算,我们就可以将( |xi−xe| + |yi−ye| ) % ki 转变为去掉绝对值的n个等式,然后以每个区域的左下角(代码中用Lx[i], Ly[i] 表示)作为起点,每次移动dx, dy的距离,其中 0 <= dx < lcm 并且 0 <= ly < lcm。

现在就走到了 ( Lx[i] + dx ,  Ly[i] + dy) 位置,然后check该点是否符合条件,如果符合条件,我们就在该区域内找到了一个dx, dy小于lcm的特解,我们就可以就可以用 O(1) 的复杂度计算出在这个区域内与这个点相关的所有点的数量。

为什么要小于lcm?怎么计算相关的点的数量呢?

因为每知道了一个小于lcm的特解,我们就可以在这个点的基础上对x或者y加上一个lcm的倍数(前提是不会越界),此时得到的点也是一个满足条件的新解,所以我们只需要计算出该特解的x, y 能延伸几个lcm的距离,就能以 O(1) 的复杂度计算出在这个区域内与这个点相关的所有点的数量。

#include<iostream>
#include<sstream>
#include<iterator>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<vector>
#include<bitset>
#include<climits>
#include<queue>
#include<iomanip>
#include<cmath>
#include<stack>
#include<map>
#include<ctime>
#include<new>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define MT(a,b) memset(a,b,sizeof(a))
const int INF  =  0x3f3f3f3f;
const int O    =  1e6;
const int mod  =  1e6 + 3;
const int maxn =  500;
const double PI  =  acos(-1.0);
const double E   =  2.718281828459;
const long double eps = 1e-10;

int px[maxn], py[maxn], pt[maxn], pk[maxn];
int n, m;

bool check(int x, int y) {
    for(int i=0; i<n; i++)
        if((abs(px[i] - x ) + abs(py[i] - y)) % pk[i] != pt[i] )
        return false;
    return true;
}

int gcd(int a, int b) { return !b ? a : gcd(b, a % b); }

int main(){
    int T; cin >> T;
    while( T -- ){
         cin >> n >> m;
        int Lx[maxn], Ly[maxn];
        int cnt1 = 0, cnt2 = 0, S = 1;
        Lx[cnt1 ++] = 0; Ly[cnt2 ++] = 0;
        Lx[cnt1 ++] = m + 1; Ly[cnt2 ++] = m + 1;
        for(int i=0; i<n; i++) {
            cin >> px[i] >> py[i] >> pk[i] >> pt[i];
            Lx[cnt1 ++] = px[i];
            Ly[cnt2 ++] = py[i];
            S = S * pk[i] / gcd( S, pk[i] );
        }
        sort(Lx, Lx + cnt1);
        sort(Ly, Ly + cnt2);
        LL ans = 0;
        for(int i=0; i<cnt1-1; i++) {
            if(Lx[i] == Lx[i+1]) continue;
            for(int j=0; j<cnt2-1; j++) {
                if(Ly[j] == Ly[j+1]) continue;
                for(int dx=0; dx<S; dx++) for(int dy=0; dy<S; dy++) {
                    int x = dx + Lx[i];
                    int y = dy + Ly[j];
                    if(x >= Lx[i+1] || y >= Ly[j+1]) continue;
                    //if(dx + dy > S) continue;
                    if(!check(x, y)) continue;
                    int lenx = Lx[i + 1] - x - 1;
                    int leny = Ly[j + 1] - y - 1;
                    ans += 1ll * (lenx / S + 1) * (leny / S + 1);
                }
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}
/*
 1
2 1000000000
10000 10000 2 1
 10000 10000 4 3
250000000500000000

 */

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值