给你一棵 Prüfer 序列。给你三个数
这题主要是要发现一个性质,就是考虑定义 Prüfer 序列中的第
令
我们考虑记搜,记搜的答案直接存的是 lower_bound,这样我们可以省一点空间。
但是我们发现还是需要 return 掉,这样就使得 size 了。
其实
最后稍稍判一下边界即可。
这样深度小于等于
cpp
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxl = 16;
const int lim = 15;
struct Solution {
LL a, b, c;
Solution (LL a = 0, LL b = 0, LL c = 0) { this->a = a, this->b = b, this->c = c; }
inline LL calc(int x) { return a * x + b * (x >> 1) + c; }
} F[maxl][1 << maxl];
int vis[maxl][1 << maxl];
inline void addls(Solution& a, const Solution b) {
a.a += 2 * b.a + b.b;
a.c += b.c;
}
inline void addrs(Solution& a, const Solution b) {
a.a += 2 * b.a + b.b;
a.c += b.a + b.c;
}
int kase;
#define jian(x, y) { \
x -= y; \
}
inline Solution f(int k, int first, int m, int d, bool h) {
if (k == 1) {
return Solution(0, 1, 0);
}
int siz = (1 << k) - 1;
if (siz < first || !m) {
return Solution(0, 0, 0);
}
bool flg = k <= lim && h && first + m * d >= siz;
if (flg) {
if (vis[k][first] == kase) {
return F[k][first];
}
}
int fstbak = first;
Solution ans;
int sizs = (1 << (k - 1)) - 1;
Solution xx;
if (first < sizs && m > 0) {
int nowm = min(m, (sizs - first - 1) / d + 1);
addls(ans, xx = f(k - 1, first, nowm, d, true));
first += nowm * d;
m -= nowm;
}
jian(first, sizs);
if (!h) {
if (m > 0 && !first) {
ans.a += 2, ans.c++;
first += d, m--;
}
jian(first, 1);
}
if (first < sizs && m > 0) {
int nowm = min(m, (sizs - first - 1) / d + 1);
addrs(ans, xx = f(k - 1, first, nowm, d, h));
first += nowm * d;
m -= nowm;
}
jian(first, sizs);
if (h && m > 0) {
ans.b++;
}
if (flg) {
vis[k][fstbak] = kase;
F[k][fstbak] = ans;
}
return ans;
}
int main() {
int k, q;
cin >> k >> q;
while (q--) {
int a, d, m;
cin >> a >> d >> m;
a--, kase++;
Solution ans = f(k, a, m, d, false);
cout << ans.a + ans.c << '\n';
}
return 0;
}