题解:P11612 [PA 2016] 台球 / Bilard Hilberta
cancan123456 · · 题解
感觉不难啊,为什么评黑呢?
首先我们手玩一下,可以感受到小球的运动大概这样:
那么我们只需要算出这几段线的长度,就能递归下去求解子问题了,线段长度的计算可以 DP 做到
然后来考虑一下子问题的形式,有三类子问题。
怎么求解这三类子问题呢,首先特判
还是考虑分治,对于一类子问题,考虑小球的轨迹(例如
考虑怎么分解成
对于二类子问题,仍然是同样的思路,把路径从
对于三类子问题,需要对
对这些拆分合法性的证明繁而不难,只需要归纳即可,注意拆分在
为了计算出
每次递归
#include <cstdio>
#include <utility>
using namespace std;
const int N = 35;
typedef long long ll;
ll f[N], g[N], h[N], sf[N], f0[N], f1[N], g0[N], g1[N], h0[N], h1[N], sh[N];
void pre() {
f[1] = 6;
sf[1] = 4;
g[1] = 2;
h[1] = 2;
f0[1] = 6;
f1[1] = 0;
g0[1] = 2;
g1[1] = 0;
h0[1] = 2;
h1[1] = 0;
sh[1] = 4;
for (int i = 2; i <= 30; i++) {
f[i] = g[i - 1] + 1 + h[i - 1] + 1 + f[i - 1] + g[i - 1] + 2 + f[i - 1] + g[i - 1] + 1 + h[i - 1] + 1 + g[i - 1];
sf[i] = h[i - 1] + 1 + f[i - 1] + g[i - 1] + 2 + f[i - 1] + g[i - 1] + 1 + h[i - 1];
g[i] = f[i - 1] + 2 + g[i - 1];
h[i] = h[i - 1] + 1 + g[i - 1] + g[i - 1] + 1 + h[i - 1];
f0[i] = g0[i - 1] + g0[i - 1];
f1[i] = g1[i - 1] + 1 + sf[i] + 1 + g1[i - 1];
g0[i] = f0[i - 1] + g0[i - 1];
g1[i] = f1[i - 1] + 2 + g1[i - 1];
h0[i] = h0[i - 1] + h0[i - 1];
h1[i] = h1[i - 1] + 1 + g[i - 1] + g[i - 1] + 1 + h1[i - 1];
sh[i] = g[i - 1] + g[i - 1];
}
}
pair < ll, ll > rotate(pair < ll, ll > point, pair < ll, ll > center, int dir) {
dir = (dir % 4 + 4) % 4;
if (dir == 0) {
return point;
}
pair < ll, ll > delta = make_pair(point.first - center.first, point.second - center.second);
if (dir == 1) {
return make_pair(center.first + delta.second, center.second - delta.first);
} else if (dir == 2) {
return make_pair(center.first - delta.first, center.second - delta.second);
} else {
return make_pair(center.first - delta.second, center.second + delta.first);
}
}
int get_UL(int dir) {
static const int table[4] = {0, 2, 1, 3};
return table[dir];
}
int get_UR(int dir) {
static const int table[4] = {0, 1, 3, 2};
return table[dir];
}
int get_DL(int dir) {
static const int table[4] = {1, 0, 2, 3};
return table[dir];
}
int get_DR(int dir) {
static const int table[4] = {3, 1, 2, 0};
return table[dir];
}
int upside_down(int dir) {
if (dir % 2 == 0) {
return dir ^ 2;
} else {
return dir;
}
}
pair < ll, ll > solve1(ll, int, int, int);
ll get_time1(int, int, int);
pair < ll, ll > solve0(ll, int, int);
ll get_time0(int, int);
ll get_time00(int, int);
ll get_time01(int, int);
ll get_time_medium(int, int);
pair < ll, ll > solve2(ll, int, int);
pair < ll, ll > solve1(ll t, int n, int dir1, int dir2) {
if (n == 1) {
return solve0(t, n, dir1);
}
ll tt;
tt = get_time1(n - 1, get_DL(dir1), get_UL(dir2));
if (t <= tt) {
return solve1(t, n - 1, get_DL(dir1), get_UL(dir2));
}
t -= tt + 1;
tt = get_time_medium(n, upside_down(dir2));
if (t <= tt) {
pair < ll, ll > temp = solve2(t, n, upside_down(dir2));
return make_pair(temp.first, -temp.second);
}
t -= tt + 1;
pair < ll, ll > temp = solve1(t, n - 1, get_DR(dir1), get_UR(dir2));
return make_pair((1 << n) + temp.first, temp.second);
}
ll get_time1(int n, int dir1, int dir2) {
if (n == 1) {
return get_time0(n, dir1);
} else {
return get_time00(n, dir1) + get_time01(n, upside_down(dir2));
}
}
pair < ll, ll > solve0(ll t, int n, int dir) {
if (n == 1) {
if (dir == 0) {
static const int table1[7] = {1, 2, 3, 2, 1, 2, 3};
static const int table2[7] = {0, 1, 2, 3, 2, 1, 0};
return make_pair(table1[t], table2[t]);
} else {
return make_pair(t + 1, t % 2);
}
}
ll tt;
tt = get_time0(n - 1, get_DL(dir));
if (t <= tt) {
return solve0(t, n - 1, get_DL(dir));
}
t -= tt + 1;
tt = get_time_medium(n, dir);
if (t <= tt) {
return solve2(t, n, dir);
}
t -= tt + 1;
pair < ll, ll > temp = solve0(t, n - 1, get_DR(dir));
return make_pair((1 << n) + temp.first, temp.second);
}
ll get_time0(int n, int dir) {
if (dir == 0) {
return f[n];
} else if (dir == 2) {
return h[n];
} else {
return g[n];
}
}
ll get_time00(int n, int dir) {
if (dir == 0) {
return f0[n];
} else if (dir == 2) {
return h0[n];
} else {
return g0[n];
}
}
ll get_time01(int n, int dir) {
if (dir == 0) {
return f1[n];
} else if (dir == 2) {
return h1[n];
} else {
return g1[n];
}
}
ll get_time_medium(int n, int dir) {
if (dir == 0) {
return sf[n];
} else if (dir == 2) {
return sh[n];
} else {
return 0;
}
}
pair < ll, ll > solve2(ll t, int n, int dir) {
if (n == 1) {
if (dir == 0) {
static const int tablex[5] = {2, 3, 2, 1, 2};
static const int tabley[5] = {1, 2, 3, 2, 1};
return make_pair(tablex[t], tabley[t]);
} else {
return make_pair(2, 1);
}
}
ll tt;
if (dir == 0) {
tt = get_time1(n - 1, 2, 0);
if (t <= tt) {
pair < ll, ll > temp = solve1(t, n - 1, 2, 0);
return make_pair((1 << n) + temp.second, temp.first);
}
t -= tt + 1;
tt = get_time1(n - 1, 0, 3);
if (t <= tt) {
pair < ll, ll > temp = solve1(t, n - 1, 0, 3);
return make_pair((1 << n) - temp.first, (1 << n) + temp.second);
}
t -= tt;
tt = get_time1(n - 1, 1, 2);
if (t <= tt) {
pair < ll, ll > temp = solve1(t, n - 1, 1, 2);
return make_pair(temp.first, (1 << n) - temp.second);
}
t -= tt + 1;
if (t == 0) {
return make_pair(1 << n, (1 << n) + 1);
}
t--;
tt = get_time1(n - 1, 3, 2);
if (t <= tt) {
pair < ll, ll > temp = solve1(t, n - 1, 3, 2);
return make_pair((1 << n) + temp.first, (1 << n) - temp.second);
}
t -= tt;
tt = get_time1(n - 1, 0, 1);
if (t <= tt) {
pair < ll, ll > temp = solve1(t, n - 1, 0, 1);
return make_pair((2ll << n) - temp.first, (1 << n) + temp.second);
}
t -= tt + 1;
pair < ll, ll > temp = solve1(t, n - 1, 2, 0);
return make_pair((1 << n) - temp.second, (1 << n) - temp.first);
} else if (dir == 2) {
tt = get_time1(n - 1, 3, 3);
if (t <= tt) {
pair < ll, ll > temp = solve1(t, n - 1, 3, 3);
return make_pair((1 << n) + temp.second, temp.first);
}
t -= tt;
pair < ll, ll > temp = solve1(t, n - 1, 1, 1);
return make_pair((1 << n) - temp.second, (1 << n) - temp.first);
} else {
return make_pair(1 << n, 1);
}
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
pre();
int n, m;
scanf("%d %d", &n, &m);
for (ll t; m != 0; m--) {
scanf("%lld", &t);
for (int i = 0; i < 4; i++) {
ll tt = get_time0(n, i);
if (t <= tt) {
pair < ll, ll > ans = rotate(solve0(t, n, i), make_pair(1 << n, 1 << n), -i);
printf("%lld %lld\n", ans.first, ans.second);
break;
} else {
t -= tt + 1;
}
}
}
return 0;
}