#include <cmath>
#include <algorithm>
#include <numeric>
#include <vector>
#include <iostream>
#include <set>
#include <string>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <limits>
#include <functional>
#include <stack>
#include <queue>
#include <random>
using namespace std;
struct Point2D
{
int x;
int y;
bool operator==(const Point2D& other) const
{
return x * other.y == y * other.x;
}
};
static int gcd (int a, int b){
a = abs(a); b = abs(b);
return (b==0) ? a : gcd(b, a%b);
}
namespace std
{
template <>
struct hash<Point2D>
{
std::size_t operator()(const Point2D& k) const
{
// Compute individual hash values for first,
// second and combine them using XOR
// and bit shifting:
int g = gcd(k.x, k.y);
int a = k.x/g, b = k.y/g;
return a ^ b;
/*
int i1 = k.x;
int i2 = k.y;
size_t ret = i1;
ret *= 2654435761U;
return ret ^ i2;
*/
/*
return 111;
*/
}
};
}
int solution(vector<Point2D> &A)
{
unordered_set<Point2D> pointsOnTheSameLine;
for (auto& point : A)
{
pointsOnTheSameLine.insert(point);
}
return static_cast<int>(pointsOnTheSameLine.size());
}
int main()
{
std::random_device rd; // only used once to initialise (seed) engine
std::mt19937 rng(rd()); // random-number engine used (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(-10000, 10000); // guaranteed unbiased
int x = 13;
int y = 7;
vector<Point2D> v; // { {0, 1}, {0, 2}, {1, 1}, {-1, -1} };
for (int i = 0; i < 1000; ++i)
{
auto random_integer = uni(rng);
const Point2D curr{x * random_integer, y * random_integer};
v.push_back(curr);
//cout << "is equal: " << (Point2D{x, y} == curr) << endl;
}
cout << solution(v) << endl;
return 0;
}
I2luY2x1ZGUgPGNtYXRoPgojaW5jbHVkZSA8YWxnb3JpdGhtPgojaW5jbHVkZSA8bnVtZXJpYz4KI2luY2x1ZGUgPHZlY3Rvcj4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8c2V0PgojaW5jbHVkZSA8c3RyaW5nPgojaW5jbHVkZSA8bWFwPgojaW5jbHVkZSA8dW5vcmRlcmVkX21hcD4KI2luY2x1ZGUgPHVub3JkZXJlZF9zZXQ+CiNpbmNsdWRlIDxsaW1pdHM+CiNpbmNsdWRlIDxmdW5jdGlvbmFsPgojaW5jbHVkZSA8c3RhY2s+CiNpbmNsdWRlIDxxdWV1ZT4KI2luY2x1ZGUgPHJhbmRvbT4KdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCgpzdHJ1Y3QgUG9pbnQyRAp7CiAgICBpbnQgeDsKICAgIGludCB5OwoKICAgIGJvb2wgb3BlcmF0b3I9PShjb25zdCBQb2ludDJEJiBvdGhlcikgY29uc3QKICAgIHsKICAgICAgICByZXR1cm4geCAqIG90aGVyLnkgPT0geSAqIG90aGVyLng7CiAgICB9Cn07CgpzdGF0aWMgaW50IGdjZCAoaW50IGEsIGludCBiKXsKICAgIGEgPSBhYnMoYSk7IGIgPSBhYnMoYik7CiAgICByZXR1cm4gKGI9PTApID8gYSA6IGdjZChiLCBhJWIpOwp9CgpuYW1lc3BhY2Ugc3RkCnsKICAgIHRlbXBsYXRlIDw+CiAgICBzdHJ1Y3QgaGFzaDxQb2ludDJEPgogICAgewogICAgICAgIHN0ZDo6c2l6ZV90IG9wZXJhdG9yKCkoY29uc3QgUG9pbnQyRCYgaykgY29uc3QKICAgICAgICB7CiAgICAgICAgICAgIC8vIENvbXB1dGUgaW5kaXZpZHVhbCBoYXNoIHZhbHVlcyBmb3IgZmlyc3QsCiAgICAgICAgICAgIC8vIHNlY29uZCBhbmQgY29tYmluZSB0aGVtIHVzaW5nIFhPUgogICAgICAgICAgICAvLyBhbmQgYml0IHNoaWZ0aW5nOgogICAgICAgICAgICBpbnQgZyA9IGdjZChrLngsIGsueSk7CiAgICAgICAgICAgIGludCBhID0gay54L2csIGIgPSBrLnkvZzsKICAgICAgICAgICAgcmV0dXJuIGEgXiBiOwoKICAgICAgICAgICAgLyoKICAgICAgICAgICAgaW50IGkxID0gay54OwogICAgICAgICAgICBpbnQgaTIgPSBrLnk7CiAgICAgICAgICAgIHNpemVfdCByZXQgPSBpMTsKICAgICAgICAgICAgcmV0ICo9IDI2NTQ0MzU3NjFVOwogICAgICAgICAgICByZXR1cm4gcmV0IF4gaTI7CiAgICAgICAgICAgICovCgogICAgICAgICAgICAvKgogICAgICAgICAgICByZXR1cm4gMTExOwogICAgICAgICAgICAqLwogICAgICAgIH0KICAgIH07Cgp9CgppbnQgc29sdXRpb24odmVjdG9yPFBvaW50MkQ+ICZBKQp7CiAgICB1bm9yZGVyZWRfc2V0PFBvaW50MkQ+IHBvaW50c09uVGhlU2FtZUxpbmU7CgogICAgZm9yIChhdXRvJiBwb2ludCA6IEEpCiAgICB7CiAgICAgICAgcG9pbnRzT25UaGVTYW1lTGluZS5pbnNlcnQocG9pbnQpOwogICAgfQoKICAgIHJldHVybiBzdGF0aWNfY2FzdDxpbnQ+KHBvaW50c09uVGhlU2FtZUxpbmUuc2l6ZSgpKTsKfQoKaW50IG1haW4oKQp7CiAgICBzdGQ6OnJhbmRvbV9kZXZpY2UgcmQ7ICAgICAvLyBvbmx5IHVzZWQgb25jZSB0byBpbml0aWFsaXNlIChzZWVkKSBlbmdpbmUKICAgIHN0ZDo6bXQxOTkzNyBybmcocmQoKSk7ICAgIC8vIHJhbmRvbS1udW1iZXIgZW5naW5lIHVzZWQgKE1lcnNlbm5lLVR3aXN0ZXIgaW4gdGhpcyBjYXNlKQogICAgc3RkOjp1bmlmb3JtX2ludF9kaXN0cmlidXRpb248aW50PiB1bmkoLTEwMDAwLCAxMDAwMCk7IC8vIGd1YXJhbnRlZWQgdW5iaWFzZWQKCiAgICBpbnQgeCA9IDEzOwogICAgaW50IHkgPSA3OwogICAgdmVjdG9yPFBvaW50MkQ+IHY7IC8vIHsgezAsIDF9LCB7MCwgMn0sIHsxLCAxfSwgey0xLCAtMX0gfTsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgMTAwMDsgKytpKQogICAgewogICAgICAgIGF1dG8gcmFuZG9tX2ludGVnZXIgPSB1bmkocm5nKTsKICAgICAgICBjb25zdCBQb2ludDJEIGN1cnJ7eCAqIHJhbmRvbV9pbnRlZ2VyLCB5ICogcmFuZG9tX2ludGVnZXJ9OwogICAgICAgIHYucHVzaF9iYWNrKGN1cnIpOwoKICAgICAgICAvL2NvdXQgPDwgImlzIGVxdWFsOiAiIDw8IChQb2ludDJEe3gsIHl9ID09IGN1cnIpIDw8IGVuZGw7CiAgICB9CgoKCiAgICBjb3V0IDw8IHNvbHV0aW9uKHYpIDw8IGVuZGw7CgogICAgcmV0dXJuIDA7Cn0K