AtCoder題解——Beginner Contest 168——E - ∙ (Bullet)

題目相關

題目鏈接

AtCoder Beginner Contest 168 E題,https://atcoder.jp/contests/abc168/tasks/abc168_e

Problem Statement

We have caught N sardines. The deliciousness and fragrantness of the ii-th sardine is Ai and Bi, respectively.

We will choose one or more of these sardines and put them into a cooler. However, two sardines on bad terms cannot be chosen at the same time.

The ii-th and j-th sardines (i≠j) are on bad terms if and only if Ai⋅Aj+Bi⋅Bj=0.

In how many ways can we choose the set of sardines to put into the cooler? Since the count can be enormous, print it modulo 1000000007.

Input

Input is given from Standard Input in the following format:

N
A1 B1
:
AN BN

Output

Print the count modulo 1000000007.

Samples1

Sample Input 1

3
1 2
-1 1
2 -1

Sample Output 1

5

Explaination

There are five ways to choose the set of sardines, as follows:

  • The 1-st
  • The 1-st and 2-nd
  • The 2-nd
  • The 2-nd and 3-rd
  • The 3-rd

Samples2

Sample Input 2

10
3 2
3 2
-1 1
2 -1
-3 -9
-8 12
7 7
8 1
8 2
8 4

Sample Output 2

479

Constraints

  • All values in input are integers.
  • 1 ≤ N ≤ 2×10^5
  • −10^18 ≤ Ai, Bi ≤10^18

題解報告

非常慚愧,本題在現場比賽的時候,我竟然沒有 AC。

題目翻譯

我們抓住 N 條沙丁魚,第 i 條魚的美味度和芳香度分別用 Ai 和 Bi 表示。現在我們將選擇一條或者兩條條沙丁魚放置到冷櫃中,如果 A_{i}\cdot A_{j}+B_{i}\cdot B_{j}=0,那麼這第 i 條和第 j 條沙丁魚就不能放在一起。

問我們有多少种放置的方法。由於數據會比較大,請將答案對 1000000007 取模。

題目分析

可能不少人看到題目的時候,都不知道題目深層次到底說什麼。我開始的時候,這個題目也沒有完全讀懂。第一反應是暴力枚舉,但是看到了數據集 N 的大小,暴力枚舉肯定是無法通過。

數學知識

向量的點乘

我們仔細的看一下題目中提到的公式:A_{i}\cdot A_{j}+B_{i}\cdot B_{j}=0,是不是看上去很眼熟?不錯,這不就是向量中的點乘的定義嗎?所以還是強調一下,算法核心還是數學。這個公式的表示向量 A 和 B 是垂直的,如下圖。

模的化簡

向量有兩個要素:模和幅角。如上圖所示的向量,我們可以將他們的 (Ai, Aj) 進行化簡,化簡的目的是爲了降低數據的複雜度,也就是降低了有效的 N 的範圍。 

化簡的方法也簡單,就是除以 Ai 和 Aj 的最大公約數即可。

幅角的化簡

本題中,幅角沒有什麼意義,因此我們可以將第三象限的向量轉換爲第一象限,將第二象限的向量轉換爲第四象限。這個處理的目的和模化簡得目的是一樣的。

最終答案

如上圖所示,我們有若干個向量互相垂直,注意不垂直的向量沒有繪製。

我們選擇任意一個向量,假設其座標爲 (x, y)。

1、有 K1 個向量,與該向量不垂直。這種情況下每個屬於該類的沙丁魚,我們可以選或者不選。顯然存在 2^{K1} 種方案,

2、有 K2 個向量,與該向量垂直。這種情況下每個屬於該類的沙丁魚,我們只能選擇兩種中的一個。因此方案爲 2^{K1}+2^{K2}

由於兩種方案都不選在上面多算了一次,所以總方案數位:2^{K1}+2^{K2}-1

樣例數據分析

樣例數據 1

根據樣例數據 1,我們可以繪製出分佈如下圖。

根據題目的要求,放置沙丁魚的原則有兩種:

1、一條放置。這樣我們有 3 種選擇:即單獨放第 1 條;單獨放第 2 條;單獨放第 3 條.

2、兩條放置。如上圖所示,我們知道綠色和紅色是垂直關係。這樣我們有 2 種選擇:放置 1 和 2;放置 1 和 3;放置 2 和 3。

合計是 2+3=5 種。

根據上面的計算公式:對於 (1, 2) 這個向量,和它不垂直有 2 個,和它垂直有 1 個,因此根據計算公式:K1=2,K2=1,2^{2}+2^{1}-1=4+2-1=6-1=5

樣例數據 2

有點多,我偷懶了,略。

數據表示

我們可以將每一個 Ai, Aj 用 map 來表示。定義方法如下:

map<pair<long long, long long>, long long> m;

也就是統計 (Ai, Aj) 這樣的最簡向量個數。

算法設計

1、逐個讀取 Ai 和 Aj。

2、如果 Ai 和 Aj 同時爲零。記錄這樣向量個數,後續的處理就不需要了。

3、如果 Ai 和 Aj 不同時爲零。進行約分處理和象限處理。生成 map 對。

4、遍歷 map,進行有效性檢查。

OI 知識點

1、快速冪。

2、最小公約數。

3、餘數相關定理。即如何取模。

AC 參考代碼

#include <bits/stdc++.h>

using namespace std;

const long long MOD=1e9+7;

long long quick_power(long long x, long long y, long long p) {
    long long ans=1;
    while (y) {
        if (y&1) {
            ans=(ans*x)%p; 
        }
        y>>=1;
        x=(x*x)%p;
    }
    return ans%p;
}

int main() {
    long long n;
    long long zeros = 0;
    long long ans=1;

    map<pair<long long,long long>,long long> m;
    map<pair<long long,long long>,long long>::iterator it;

    scanf("%lld", &n);
    for (long long i=1; i<=n; i++) {
        long long u,v,now;
        scanf("%lld%lld", &u, &v);

        if (u==0&&v==0) {
            zeros++;
            continue;
        }

        now=__gcd(u,v);
        u/=now;
        v/=now;

        if (u<0) {
            u=-u;
            v=-v;
        }
        m[make_pair(u,v)]++;
    }

    for (it=m.begin();it!=m.end();it++) {
        if (it->second==0) {
            continue;
        }

        long long x=it->first.first,y=it->first.second;
        long long p=quick_power(2, m[make_pair(x,y)], MOD);

        y=-y;
        if (y<0) {
            x=-x;
            y=-y;
        } 

        if (m.count(make_pair(y,x))) {
            p=(p+quick_power(2, m[make_pair(y,x)], MOD)-1);
            m[make_pair(y,x)]=0;
        }
        ans=(ans*p)%MOD;
    }

    printf("%lld\n", ((ans+zeros-1)%MOD+MOD)%MOD);
	
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章