#include "triples.h"
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
using vi = vector<int>;
using vvi = vector<vi>;
using vl = vector<ll>;
using vvl = vector<vl>;
using pi = pair<int, int>;
#define FOR(i, a, b) for (int i = a; i < b; i++)
#define ROF(i, a, b) for (int i = a; i >= b; i--)
#define each(a, x) for (auto &a : x)
#define all(x) (x).begin(), (x).end()
#define bg(x) (x).begin()
#define en(x) (x).end()
#define rev(x) reverse(all(x))
#define sz(x) int((x).size())
#define srt(x) sort(all(x))
#define cnt(a, x) count(all(x), a)
#define trace(x) each(a, (x)) cout << a << " "
#define mp make_pair
#define pb push_back
#define lb lower_bound
#define ub upper_bound
ll brute(vi h) {
int n = sz(h);
ll ans = 0;
FOR(i, 0, n) {
FOR(j, i+1, n) {
FOR(k, j+1, n) {
int d1 = min({k-j, k-i,j-i}), d3 = max({k-j, j-i, k-i}), f1 = min({h[i], h[j], h[k]}), f3 = max({h[i], h[j], h[k]});
int d2 = (k-j) ^ (k-i) ^ (j-i) ^ d1 ^ d3, f2 = h[i] ^ h[j] ^ h[k] ^ f1 ^ f3;
if (d1 == f1 && d2 == f2 && d3 == f3) ans++;
}
}
}
return ans;
}
struct Triple {
int i, j, k;
Triple() {};
Triple(int I, int J, int K) {
i = min({I, J, K});
k = max({I, J, K});
j = (I ^ J ^ K) ^ i ^ k; // lol
}
const bool operator<(const Triple &other) const {
if (i != other.i) return i < other.i;
if (j != other.j) return j < other.j;
return k < other.k;
}
};
ll count_triples(vi h) {
int n = sz(h);
ll ans = 0;
FOR(i, 0, n) { // count number of triples where h[i] = d(i, j) or d(i, k)
int H = h[i];
set<Triple> trips; // prevent double count with dupe height
int j = i + H;
if (j < n) {
int k1 = i + h[j], k2 = j + h[j]; // 2 cases — h[j] = d(i, k) or h[j] = d(j, k)
if (k1 < n && h[k1] == (k1 - j)) trips.insert(Triple(i, j, k1)); // we know d(i, j) and d(i, k) to be h[i] and h[j], so does h[k] == d(j, k)
if (k2 < n && h[k2] == (k2 - i)) trips.insert(Triple(i, j, k2)); // symmetric but this time for i
}
int k = i + H;
if (k < n) {
int j1 = i + h[k], j2 = k - h[k]; // h[k] = d(i, k), h[k] = d(j, k)
if ((i < j1 && j1 < k) && h[j1] == (k - j1)) trips.insert(Triple(i, j1, k));
if ((i < j2 && j2 < k) && h[j2] == (j2 - i)) trips.insert(Triple(i, j2, k));
}
for (auto &el : trips) {
if (h[el.j] != h[el.i] && h[el.k] != h[el.i]) ans++;
}
}
unordered_map<int, vector<int>> pc, nc; // positive line intercepts, negative line intercepts
vi inp(n), inn(n); // lookup for the intercept
FOR(i, 0, n) {
int c1 = h[i] - i, c2 = h[i] + i;
inp[i] = c1, inn[i] = c2;
pc[c1].pb(i), nc[c2].pb(i);
}
for (auto &cnst : pc) { // count number of triples where h[j] = d(i, j), h[k] = d(i, k), and h[i] = d(j, k) = h[k] - h[j]
int i = -cnst.first;
if (i < 0 || i >= n) continue;
int H = h[i];
for (auto &el : cnst.second) {
int j = el, k = el + H;
if (k >= n) break;
if (inp[k] != inp[j]) continue;
ans++;
}
}
FOR(j, 0, n) { // count number of triples where h[j] = d(i, k), h[k] = d(i, j) and h[i] = d(j, k) = h[j] - h[k]
int f1 = lower_bound(all(pc[inp[j]]), j-h[j]) - bg(pc[inp[j]]);
int f2 = upper_bound(all(nc[inn[j]]), j+h[j]) - bg(nc[inn[j]]);
int p1 = lower_bound(all(pc[inp[j]]), j) - bg(pc[inp[j]]), p2 = lower_bound(all(nc[inn[j]]), j) - bg(nc[inn[j]]);
if (p1 - f1 < f2 - p2) { // there is no way to set up the diagonals such that no matter which way you go its n^2
for (int el = f1; el < p1; el++) {
int i = pc[inp[j]][el];
int dist = j - i;
if (j + h[i] >= n || h[j + h[i]] != dist) continue;
ans++;
}
} else {
for (int el = p2 + 1; el < f2; el++) {
int k = nc[inn[j]][el];
int dist = k - j;
if (j - h[k] < 0 || h[j - h[k]] != dist) continue;
ans++;
}
}
}
return ans;
}
bool accept(double cur_score, double next_score, double temp, mt19937 &rng) {
if (next_score > cur_score) return true;
cur_score = -cur_score; next_score = -next_score;
double prob = exp(-(next_score - cur_score) / temp);
return generate_canonical<double, 53>(rng) < prob;
}
vi construct_range(int M, int K) {
vi best(M, 1);
int score = 0, best_score = 0;
for (int tl = 0; tl < 2; tl++) {
vi cur(M, 1);
score = 0;
// double T = 10000, u = 0.9995;
double t0 = 100, c = 1.0;
int trials = 1;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
uniform_int_distribution u(0, M-1);
geometric_distribution<int> g(0.4);
double lambda = 0.1; vector<double> w(M); for (int i = 0; i < M; i++) w[i] = exp(-lambda * i);
discrete_distribution<int> d(all(w));
// while (T > 1) {
int lim = (150'000 / M) * 20;
while(trials < lim && best_score < K) {
if (best_score >= K) break;
if (trials % 10000 == 0) cerr << "Trials: " << trials << " Best: " << best_score << "\n";
double T = c / log(t0 + double(trials));
vi nxt = cur;
int idx = u(rng);
// int val = g(rng) + 1; while (val >= M) val = g(rng) + 1;
int val = u(rng); while (!(1 <= val && val < M)) val = u(rng);
nxt[idx] = val;
int ns = count_triples(nxt);
if (accept(score, ns, T, rng)) {
score = ns; cur = nxt;
if (ns > best_score) {
best_score = ns; best = nxt;
}
}
// T *= u;
trials++;
}
}
cerr << "Array has: " << count_triples(best) << " triples.\n";
return best;
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |