QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#451659 | #8779. Square of Triangles | ideograph_advantage | WA | 321ms | 43712kb | C++20 | 23.3kb | 2024-06-23 17:20:54 | 2024-06-23 17:20:54 |
Judging History
answer
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
#ifdef zisk
void __print(int x) {cerr << x;}
void __print(long x) {cerr << x;}
void __print(long long x) {cerr << x;}
void __print(unsigned x) {cerr << x;}
void __print(unsigned long x) {cerr << x;}
void __print(unsigned long long x) {cerr << x;}
void __print(float x) {cerr << x;}
void __print(double x) {cerr << x;}
void __print(long double x) {cerr << x;}
void __print(char x) {cerr << '\'' << x << '\'';}
void __print(const char *x) {cerr << '\"' << x << '\"';}
void __print(const string &x) {cerr << '\"' << x << '\"';}
void __print(bool x) {cerr << (x ? "true" : "false");}
template<typename T, typename V>
void __print(const pair<T, V> &x) {cerr << '{'; __print(x.first); cerr << ','; __print(x.second); cerr << '}';}
template<typename T>
void __print(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), __print(i); cerr << "}";}
void _print() {cerr << "]\n";}
template <typename T, typename... V>
void _print(T t, V... v) {__print(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
#define debug(x...) cerr << "[" << #x << "] = [", _print(x)
template<class T> void pary(T l, T r) {
while (l != r) cout << *l << " ", l++;
cout << endl;
}
#else
#define debug(x...) (void)0
template<class T> void pary(T l, T r) {}
#endif
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
#define vi vector<int>
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define pii pair<int,int>
#define pll pair<ll,ll>
#define F(n) Fi(i,n)
#define Fi(i,n) Fl(i,0,n)
#define Fl(i,l,n) for(int i=l;i<n;i++)
#define RF(n) RFi(i,n)
#define RFi(i,n) RFl(i,0,n)
#define RFl(i,l,n) for(int i=n-1;i>=l;i--)
#define all(v) begin(v),end(v)
#define siz(v) ((long long)(v.size()))
#define get_pos(v,x) (lower_bound(all(v),x)-begin(v))
#define sort_uni(v) sort(begin(v),end(v)),v.erase(unique(begin(v),end(v)),end(v))
#define mem(v,x) memset(v,x,sizeof v)
#define ff first
#define ss second
#define RAN(a,b) uniform_int_distribution<int> (a, b)(rng) // inclusive
#define cmax(a,b) (a = max(a,b))
#define cmin(a,b) (a = min(a,b))
typedef long long ll;
typedef long double ld;
/* TEMPLATE STARTS HERE */
namespace factorization{ // {{{ primality test and factorization
class RNG { // RANDOM NUMBER GENERATOR
private:
mt19937_64 mt;
public:
RNG() : mt(chrono::steady_clock::now().time_since_epoch().count()) {}
int64_t operator()(int64_t L, int64_t R) {
uniform_int_distribution<int64_t> dist(L, R - 1);
return dist(mt);
}
int64_t operator()(int64_t r) { return (*this)(0, r); }
} Rng;
class Mint // MODULAR INTEGERS IN MONTGOMERY FORM
{
private:
using u64 = uint64_t;
using u128 = __uint128_t;
// CLASS MEMBER DATA
static u64 mod;
static u64 N; // mod * N ≡ -1 MOD 2^64
static u64 R; // 2^128 MOD mod
u64 a;
public:
Mint() = default;
Mint(int64_t b) : a(reduce(u128(b) * R)){};
// GETS AND SETS
static u64 get_mod() { return mod; }
u64 get() const {
u64 ret = reduce(a);
return ret >= mod ? ret - mod : ret;
}
static void set_mod(u64 m) {
N = mod = m;
for (int i = 0; i < 5; ++i) N *= 2 - m * N;
N = -N;
R = -u128(m) % m;
}
// OPERATORS
Mint &operator+=(const Mint &b) {
if (int64_t(a += b.a - 2 * mod) < 0) a += 2 * mod;
return *this;
}
Mint &operator-=(const Mint &b) {
if (int64_t(a -= b.a) < 0) a += 2 * mod;
return *this;
}
Mint &operator*=(const Mint &b) {
a = reduce(u128(a) * b.a);
return *this;
}
Mint operator+(const Mint &b) const { return Mint(*this) += b; }
Mint operator-(const Mint &b) const { return Mint(*this) -= b; }
Mint operator*(const Mint &b) const { return Mint(*this) *= b; }
Mint operator-() const { return Mint() - Mint(*this); }
Mint &operator++() { return *this += Mint(1); }
Mint &operator--() { return *this -= Mint(1); }
bool operator==(const Mint &b) const {
return (a >= mod ? a - mod : a) == (b.a >= mod ? b.a - mod : b.a);
}
bool operator!=(const Mint &b) const {
return (a >= mod ? a - mod : a) != (b.a >= mod ? b.a - mod : b.a);
}
// METHODS
Mint pow(u64 n) const {
Mint ret(1), mul(*this);
while (n > 0) {
if (n & 1) ret *= mul;
mul *= mul;
n >>= 1;
}
return ret;
}
friend ostream &operator<<(ostream &os, const Mint &b) {
return os << b.get();
}
friend istream &operator>>(istream &is, Mint &b) {
int64_t t;
is >> t;
b = Mint(t);
return is;
}
private:
static u64 reduce(const u128 &b) {
return (b + u128(u64(b) * u64(N)) * mod) >> 64;
}
};
// NONCONSTANT STATIC CLASS MEMBERS MUST HAVE GLOBAL SCOPE
typename Mint::u64 Mint::mod, Mint::N, Mint::R;
// =================== BEGIN MILLER RABIN ===================
static inline bool isPrime(const uint64_t n) {
static constexpr uint64_t primeMask = 2891462833508853932ULL;
if (n < 64) {
return primeMask >> n & 1;
} // BITMASK SMALL PRIMES
if (!(n & 1)) return false;
Mint::set_mod(n);
uint64_t u = n - 1;
int s, t = 0;
while (!(u & 1)) ++t, u >>= 1;
// FROM http://miller-rabin.appspot.com/ SEE REMARKS
vector<uint64_t> seeds;
if (n < 1050535501ULL)
seeds = {336781006125ULL, 9639812373923155ULL};
else if (n < 350269456337ULL)
seeds = {4230279247111683200ULL, 14694767155120705706ULL,
16641139526367750375ULL};
else if (n < 55245642489451ULL)
seeds = {2ULL, 141889084524735ULL, 1199124725622454117ULL,
11096072698276303650ULL};
else if (n < 7999252175582851ULL)
seeds = {2ULL, 4130806001517ULL, 149795463772692060ULL,
186635894390467037ULL, 3967304179347715805ULL};
else if (n < 585226005592931977ULL)
seeds = {2ULL,
123635709730000ULL,
9233062284813009ULL,
43835965440333360ULL,
761179012939631437ULL,
1263739024124850375ULL};
else
seeds = {2ULL, 325ULL, 9375ULL, 28178ULL,
450775ULL, 9780504ULL, 1795265022ULL};
for (auto &a : seeds) {
uint64_t p = a < n ? a : a % n;
if (p == 0) continue;
Mint x = Mint(p).pow(u);
if (x != 1) {
for (s = 0; s < t && x != n - 1; ++s)
if ((x *= x) == 1) return false;
if (t == s) return false;
}
}
return true;
}
// ==================== END MILLER RABIN ====================
using u32 = uint32_t;
using u64 = uint64_t;
// =================== BEGIN POLLARD'S RHO ===================
u64 pollardRho(u64 n) {
if (!(n & 1)) return 2;
if (isPrime(n)) return n;
if (Mint::get_mod() != n) Mint::set_mod(n);
Mint R, one = 1;
auto f = [&](Mint x) { return x * x + R; };
auto rnd = [&]() { return Rng(n - 2) + 2; };
constexpr size_t m = 128;
while (true) {
Mint x, ys, q = one, y = rnd();
R = rnd();
u64 g = 1;
for (u64 r = 1; g == 1; r <<= 1ULL) {
x = y;
for (size_t i = 0; i < r; ++i) y = f(y);
for (size_t k = 0; g == 1 && k < r; k += m) {
ys = y;
for (size_t i = 0; i < m && i < r - k; ++i) q *= x - (y = f(y));
g = gcd(q.get(), n);
}
}
if (g == n) do {
g = gcd((x - (ys = f(ys))).get(), n);
} while (g == 1);
if (g != n) return g;
}
return 0;
}
// ==================== END POLLARD'S RHO ====================
vector<u64> findFactors(u64 n) {
if (n <= 1) return {};
u64 p = pollardRho(n);
if (p == n) return {n};
auto l = findFactors(p);
auto r = findFactors(n / p);
copy(begin(r), end(r), back_inserter(l));
return l;
}
vector<pair<u64, u32> > primeFactorization(u64 n) {
auto pf = findFactors(n);
sort(begin(pf), end(pf));
vector<pair<u64, u32> > ret;
for (auto &e : pf) {
if (!empty(ret) && ret.back().first == e)
++ret.back().second;
else
ret.emplace_back(e, 1);
}
return ret;
}
} // namespace factorization }}}
using factorization::isPrime, factorization::primeFactorization;
/* TEMPLATE ENDS HERE */
const int maxC = 1e7 + 10;
vector<bool> isprime(maxC, 1);
vector<int> PrimeFactor(maxC);
pll reduce(ll t){
if(t == 0) return {0, 1};
map<int, int > fac;
if(t >= maxC){
auto bruh = primeFactorization(t);
for(auto [x, y] : bruh){
fac[x] = y;
}
}else{
while(t > 1){
fac[PrimeFactor[t]]++;
t /= PrimeFactor[t];
}
}
pll ret = mp(1, 1);
for(auto [x, y] : fac){
if(y & 1) ret.ss *= x, y--;
while(y){
ret.ff *= x;
y -= 2;
}
}
return ret;
}
using tri = array<pll, 3>;
ll square(pll x){
return x.ff * x.ff * x.ss;
}
pll calc_cosine(tri x) { // return cosine * abs(cosine) as a fraction
ll n = square(x[1]) + square(x[2]) - square(x[0]);
n *= abs(n);
ll d = 4 * square(x[1]) * square(x[2]);
ll g = gcd(n, d);
n /= g, d /= g;
return {n, d};
}
ll calc_area (tri x) { // returns 16 A^2
ll a[3];
for(int i = 0; i < 3; i++) a[i] = square(x[i]);
ll ret1 = a[0] * a[1] + a[1] * a[2] + a[2] * a[0];
ll ret2 = 0;
for(int i = 0; i < 3; i++) ret2 += a[i] * a[i];
return 2 * ret1 - ret2;
};
vector<tri> tris(4);
vector<int> used(4);
struct iter{
vector<tri> inp;
vector<tri> ok;
vector<int> ids;
int idx;
iter(vector<tri> _tris) : inp(_tris) {}
iter(){}
void init(vector<tri> _tris){
inp = _tris;
}
void init_unused(){
for(int i = 0; i < 4; i++){
if(!used[i]) inp.push_back(tris[i]);
}
}
int get_length(pll x){
idx = 0;
int _bruh = 0;
for(auto i : inp){
sort(all(i));
do{
if(i[0] == x) ok.push_back(i), ids.push_back(_bruh);
}while(next_permutation(all(i)));
_bruh++;
}
return siz(ok);
}
int get_cosine(pll x){
idx = 0;
int _bruh = 0;
for(auto i : inp){
sort(all(i));
do{
if(calc_cosine(i) == x) ok.push_back(i), ids.push_back(_bruh);
}while(next_permutation(all(i)));
_bruh++;
}
return siz(ok);
}
tri query(){
if(idx) used[ids[idx - 1]] = 0;
if(idx == siz(ok)) return {};
else{
used[ids[idx]] = 1;
return ok[idx++];
}
}
};
bool ping (tri target, tri t1, tri t2){
{
auto at = reduce(calc_area(target));
auto a1 = reduce(calc_area(t1));
auto a2 = reduce(calc_area(t2));
if(a1.ss != at.ss || a2.ss != at.ss) return 0;
if(a1.ff + a2.ff != at.ff) return 0;
}
sort(all(target));
sort(all(t1));
do{
sort(all(t2));
do{
if(t1[0] == t2[0]){
auto s1 = t1, s2 = t2;
swap(s1[1], s1[0]), swap(s2[1], s2[0]);
auto c1 = calc_cosine(s1), c2 = calc_cosine(s2);
if(c1.ss == c2.ss && c1.ff + c2.ff == 0 && t1[2].ss == t2[2].ss){
tri tst;
tst[0] = t1[1];
tst[1] = t2[1];
tst[2] = {t1[2].ff + t1[2].ff, t1[2].ss};
sort(all(tst));
if(tst == target) return 1;
}
}
}while(next_permutation(all(t2)));
}while(next_permutation(all(t1)));
return 0;
}
bool ping2from3 (array<tri, 2> target, array<tri, 3> t){
for(auto& i : target) sort(all(i));
for(auto& i : t) sort(all(i));
for(int _ = 0; _ < 2; _++){
for(int i = 0; i < 3; i++){
if(t[i] != target[0]) continue;
vector<tri> tst;
for(int j = 0; j < 3; j++){
if(j != i) tst.push_back(t[j]);
}
if(ping(target[1], tst[0], tst[1])) return 1;
}
swap(target[0], target[1]);
}
return 0;
}
pll law_of_cosine(pll a, pll b, pll cos){
ll c = 4 * square(a) * square(b);
if(c % cos.ss != 0) return {-1, -1};
c = c / cos.ss * cos.ff;
pll d = reduce(c);
if(d.ss != 1) return {-1, -1};
ll e = square(a) + square(b) - d.ff;
return reduce(e);
}
int solve(){
for(int i = 0; i < 4; i++){
used[i] = 0;
for(int j = 0; j < 3; j++){
ll x;
cin >> x;
tris[i][j] = reduce(x);
}
sort(all(tris[i]));
}
pll side_length;
ll area;
{
vector<pll> _area(4);
for(int i = 0; i < 4; i++) _area[i] = reduce(calc_area(tris[i]));
for(int i = 1; i < 4; i++) if(_area[i].ss != _area[0].ss) return 0; else _area[0].ff += _area[i].ff;
if(_area[0].ff % 4) return 0;
if(_area[0].ss != 1) return 0;
_area[0].ff /= 4;
area = _area[0].ff;
side_length = reduce(_area[0].ff);
}
iter base;
base.init_unused();
int _c = base.get_length(side_length);
while(_c--){
tri b = base.query(); // there is at least one complete side in the result
debug(b);
tri b1 = b, b2 = b;
swap(b1[1], b1[0]);
swap(b2[2], b2[0]);
pll c1 = calc_cosine(b1), c2 = calc_cosine(b2);
if(c1.ff < 0) continue; // obtuse base
if(c2.ff < 0) continue; // obtuse base
ll current_area = reduce(calc_area(b)).ff;
if(current_area > 2 * area) continue; // height too big
else if (c2.ff == 0) {
continue; // it will be symmetric
} else if (c1.ff == 0) {
if(current_area == 2 * area){
// base triangle is cut sandwich
debug("sandwich");
array<tri, 3> parts;
{
int idx = 0;
for(int i = 0; i < 4; i++) if(used[i]) continue; else parts[idx++] = tris[i];
}
// center cut to three vertex
debug("cut from center");
{
for(auto &i : parts) sort(all(i));
sort(all(parts));
do{
do{
do{
do{
if(parts[0][0] == side_length && parts[1][0] == side_length && parts[2][0] == reduce(square(side_length) * 2)){
if(parts[0][1] == parts[1][2] && parts[1][1] == parts[2][2] && parts[2][1] == parts[0][2]) return 1;
}
}while(next_permutation(all(parts[0])));
}while(next_permutation(all(parts[1])));
}while(next_permutation(all(parts[2])));
}while(next_permutation(all(parts)));
}
debug("cut one first");
// cut one first
{
vector<pll> st = {side_length, side_length, reduce(square(side_length) * 2)};
vector<pll> at = {{0LL, 1LL}, {1LL, 2LL}, {1LL, 2LL}};
vector<pll> lengths;
for(auto i : parts) for(auto j : i) lengths.pb(j);
sort_uni(lengths);
for(int _ = 0; _ < 3; _++){
for(auto l : lengths){
if(l.ss != st[0].ss) continue;
if(l.ff > st[0].ff) continue;
pll sl = {st[0].ff - l.ff, l.ss};
pll l2 = law_of_cosine(l, st[1], at[0]);
if(l2.ff == -1) continue;
array<tri, 2> target;
target[0] = {l, st[1], l2};
target[1] = {sl, st[2], l2};
if(ping2from3(target, parts)) return 1;
}
rotate(st.begin(), st.begin() + 1, st.end());
rotate(at.begin(), at.begin() + 1, at.end());
}
}
}else{
// base triangle cuts through a corner
debug("cut corner", b);
if(side_length.ss != b[2].ss) continue;
// four sides are side_length, side_length, b[0] , side_length - b[2],
pll sht = side_length;
sht.ff -= b[2].ff;
array<tri, 3> parts;
{
int idx = 0;
for(int i = 0; i < 4; i++) if(used[i]) continue; else parts[idx++] = tris[i];
}
// try diagonal split
debug("try diagonal split");
{
pll diag = reduce(square(side_length) + square(side_length));
array<tri, 2> target;
target[0] = {side_length, side_length, diag};
target[1] = {diag, b[1], sht};
if(ping2from3(target, parts)) return 1;
}
{
pll diag = reduce(square(side_length) + square(sht));
array<tri, 2> target;
target[0] = {side_length, b[1], diag};
target[1] = {side_length, sht, diag};
debug(target);
if(ping2from3(target, parts)) return 1;
}
// P on AB, and cut PC and PD (has to rotate four times)
debug("iterate through edge cuts");
vector<pll> sq = {side_length, side_length, b[1], sht};
vector<pll> aq = {{0LL, 1LL}, {c2.ss - c2.ff, c2.ss}, {c2.ff - c2.ss, c2.ss}, {0LL, 1LL}}; // cos * abs(cos)
vector<pll> lengths;
for(auto i : parts) for(auto j : i) lengths.pb(j);
sort_uni(lengths);
sort(all(parts));
for(int _ = 0; _ < 4; _++){
// cut on sq[0]
for(auto l : lengths){
if(l.ss != sq[0].ss) continue;
if(l.ff >= sq[0].ff) continue;
pll sl = {sq[0].ff - l.ff, l.ss};
pll l1 = law_of_cosine(l, sq[1], aq[0]);
pll l2 = law_of_cosine(sl, sq[3], aq[3]);
if(l1.ff == -1 || l2.ff == -1) continue;
array<tri, 3> cur_parts;
cur_parts[0] = {l1, l2, sq[2]};
cur_parts[1] = {l, sq[1], l1};
cur_parts[2] = {sl, sq[3], l2};
for(auto& i : cur_parts) sort(all(i));
sort(all(cur_parts));
if(parts == cur_parts) return 1;
}
rotate(sq.begin(), sq.begin() + 1, sq.end());
rotate(aq.begin(), aq.begin() + 1, aq.end());
}
}
}
else if(current_area == 2 * area){
// base triangle touch the top and cuts into two nonzero parts
// this case should be redundant as one part only has one triangle
// and that triangle can be used as base
debug("top toucher");
array<tri, 2> target;
for(int i = 1; i < 3; i++){
target[i-1] = {b[i], side_length, reduce(square(b[i])-square(side_length))};
}
array<tri, 3> parts;
{
int idx = 0;
for(int i = 0; i < 4; i++) if(used[i]) continue; else parts[idx++] = tris[i];
}
if(ping2from3(target, parts)) return 1;
} else{
// top vertex is floating inside
// one of the two angles at the base will be preserved we assume it's the right one (opposite to side 1)
// because we will process the other one eventually
debug("floating inside");
array<tri, 3> parts;
{
int idx = 0;
for(int i = 0; i < 4; i++) if(used[i]) continue; else parts[idx++] = tris[i];
}
if(c1.ff == 1 && c1.ss == 2) { // a 45 degree cut, this is the only case where a cut can transform the pentagon into two triangles
pll long_diagonal = reduce(square(side_length) * 2);
if(long_diagonal.ss == b[2].ss && long_diagonal.ff > b[2].ff){
array<tri, 2> target;
target[0] = {side_length, side_length, long_diagonal};
target[1] = {side_length, b[1], {long_diagonal.ff - b[2].ff, b[2].ss}};
if(ping2from3(target, parts)) return 1;
}
}
debug("no 45 degree cut");
// I think the cuts has to transform the shape from 5 -> 4 + 3 -> 3 + 3 + 3
// and cutting sandwich has been covered
// this leaves only the case where a center point is chosen and slices to all four vertices
// at least that's what I think anyway
{
pll a1c = {c1.ss - c1.ff, c1.ss};
pll a2c = {c2.ss - c2.ff, c2.ss};
pll l1 = law_of_cosine(b[1], side_length, a2c);
pll l2 = law_of_cosine(b[2], side_length, a1c);
if(l1.ff == -1 || l2.ff == -1) continue;
for(auto &i : parts) sort(all(i));
sort(all(parts));
array<tri, 3> tst;
tst[0] = {side_length, b[1], l1};
tst[1] = {side_length, b[2], l2};
tst[2] = {side_length, l1, l2};
for(auto &i : tst) sort(all(i));
sort(all(tst));
if(parts == tst) return 1;
}
}
}
return 0;
}
signed main(){
for(int i = 2; i < maxC; i++){
if(isprime[i]){
PrimeFactor[i] = i;
for(int j = 2; i * j < maxC; j++){
isprime[i * j] = 0;
PrimeFactor[i * j] = i;
}
}
}
cin.tie(0);
ios_base::sync_with_stdio(false);
int t;
cin >> t;
while(t--){
cout << solve() << "\n";
}
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 321ms
memory: 43572kb
input:
3 1 1 2 2 1 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 5 125 130 125 20 145 45 130 145 145 145 80
output:
1 0 1
result:
ok 3 lines
Test #2:
score: 0
Accepted
time: 258ms
memory: 43316kb
input:
20 1998001 7984010 9982009 1998001 7984010 1994005 7984010 9978013 9982009 9978013 1994005 7984010 9958045 7968034 9962037 7968034 1994005 9962037 9958045 1990013 7968034 1994005 1990013 7968034 7952074 9938097 1986025 7952074 9942085 1990013 7952074 9942085 9938097 1986025 7952074 1990013 7936130 9...
output:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
result:
ok 20 lines
Test #3:
score: -100
Wrong Answer
time: 260ms
memory: 43712kb
input:
20 1148639 3581051 1216206 9999916 7026968 270268 6013463 6013463 6756700 6013463 6013463 6756700 2608850 8630930 9445800 9862940 6448880 6939290 8631650 3682160 5184310 7504700 6652150 1917140 2359505 3170711 2299108 4027811 6760781 2960240 4679918 6106006 3178400 8153446 7975057 5222088 8849500 88...
output:
0 0 0 1 1 1 0 0 1 0 1 1 1 0 0 0 0 1 1 0
result:
wrong answer 7th lines differ - expected: '1', found: '0'