Peter's codebook A blog full of codes

PTC 2017/08 -- Problem 4

題目概述

給定大小 的格子點,這些格子點中, 四點決定一個正方形(注意:斜的也算)。

現在,拿掉某一個點 (x,y) ,使得能構成正方形的格子點集合為:

問用這些格子點,能畫出多少種不同正方形(頂點不同即視為不同)。

題目傳送門

PTC 2017/08

輸入

第一行是測資數量 T ,

後面有 T 行,

每一行有 N x y

代表 的格子點, 刪掉點

輸出

對於每一筆測資,輸出對應的正方形數量。

限制

測資數量不大於 100 筆

答案可能爆 int

範側

Input:


6
3 1 1
3 1 2
3 2 2
4 1 1
4 1 2
4 2 2

Output:


4
3
2
17
15
13

解法

想像一個由 格子點組成的框框,這個框框唯一決定了, 在框框邊線上可以構成的所有正方形組合,再移動這個框框,窮舉在 格子點中,不同的 的擺放位置。再以此方式,枚舉每一種 大小,就可以在不刪除某個點的情況下,求出 格子點可以畫出的不同正方形了。

在不刪除點的條件下,格子點可以畫出的正方形數量:

代表題目格子點大小, 代表框框大小。 掃過所有可能的 即可。

那麼,如何去掉以 為頂點的所有正方形呢?

一樣用上面框框的概念,用一個大小 的框框,讓框框的邊線貼著 ,繞一圈、數數量,即可求出所有以 為頂點的所有正方形數量了。

答案就是:

不刪掉 情況的所有正方形數量,減去所有以 為頂點的正方形數量

這個做法複雜度是

求出不刪掉點的正方形數量要

求出以 為頂點的所有正方形數量要

聽說還有更快的做法。

程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <bits/stdc++.h>
using namespace std;

long long T, n, x, y;

int main(void) {
    ios::sync_with_stdio(false);
    cin >> T;
    while(T--) {
        cin >> n >> x >> y;
        long long tot = 0;
        for (int i=2; i<=n; ++i) {
            tot += (long long)(n-i+1)*(n-i+1)*(i-1);
        }
        long long w=0, h=0;
        w = max(x-1,n-x);
        h = max(y-1,n-y);
        long long s = max(w,h);
#define IN() (tx>=1L&&ty>=1L&&tx+i<=n&&ty+i<=n)
        for (int i=1; i<=s; ++i) {
            int tx=x-i;
            int ty=y-i;
            if (IN()) --tot;
            for (int j=0; j<i; j++) {
                ++tx; if(IN()) --tot;
            }
            for (int j=0; j<i; ++j) {
                ++ty; if(IN()) --tot;
            }
            for (int j=0; j<i; ++j) {
                --tx; if(IN()) --tot;
            }
            for (int j=1; j<i; ++j) {
                --ty; if(IN()) --tot;
            }
        }
        cout << tot << '\n';
    }
    return 0;
}
comments powered by Disqus