LOJ #3217. 「PA 2019」Desant(状压dp)
考虑已经确定了前i个,状态可以只记后面的\(n-i\)个点之间的\(n-i+1\)个间隔里的已选的数。
这个状态最大是\(\sum_{k=1}^n (n/k)^k\)左右,可以发现不是很大。
注意要用多进制数去存状态,不然会被卡常。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int N = 45;
int n, a[N];
int b[N], b0;
struct nod {
ll w0, w[N];
} p, q;
void build(int *b, int &b0, nod &p) {
sort(b + 1, b + b0 + 1);
b[0] = 0; b[b0 + 1] = n + 1;
p.w0 = b0;
p.w[0] = 1;
fo(j, 1, b0 + 1) p.w[j] = p.w[j - 1] * (b[j] - b[j - 1]);
}
void zh(int *a, nod b, int x) {
fo(i, 0, b.w0) a[i] = x % b.w[i + 1] / b.w[i];
}
int zy(int *a, nod b) {
int s = 0;
fo(i, 0, b.w0) s += a[i] * b.w[i];
return s;
}
struct P {
int x; ll y;
P(int _x = 0, ll _y = 0) {
x = _x, y = _y;
}
};
P operator + (P a, P b) {
return a.x == b.x ? P(a.x, a.y + b.y) : (a.x < b.x ? a : b);
}
vector<P> f[N];
int main() {
freopen("a.in", "r", stdin);
scanf("%d", &n);
fo(i, 1, n) scanf("%d", &a[i]);
f[0].resize(1);
f[0][0] = P(0, 1);
fo(i, 0, n - 1) {
b0 = 0;
fo(j, i + 1, n) b[++ b0] = a[j];
build(b, b0, p);
int id; fo(j, 1, b0) if(b[j] == a[i + 1]) id = j;
b0 = 0;
fo(j, i + 2, n) b[++ b0] = a[j];
build(b, b0, q);
int m1 = p.w[p.w0 + 1], m2 = q.w[q.w0 + 1];
f[i + 1].resize(m2);
ff(k, 0, m2) f[i + 1][k] = P(1e9, 0);
ff(k, 0, m1) if(f[i][k].y) {
static int c[N], d[N];
zh(c, p, k);
fo(cho, 0, 1) {
P v = f[i][k];
if(cho) {
fo(u, id, p.w0) v.x += c[u];
}
int t = -1;
fo(u, 0, p.w0) {
if(u == id) {
d[t] += c[u] + cho;
} else d[++ t] = c[u];
}
int nk = zy(d, q);
f[i + 1][nk] = f[i + 1][nk] + v;
}
}
}
static P ans[N];
fo(i, 1, n) ans[i] = P(1e9, 0);
ff(k, 0, f[n].size()) {
static int c[N];
zh(c, q, k);
int x = 0;
fo(u, 0, q.w0) x += c[u];
ans[x] = ans[x] + f[n][k];
}
fo(i, 1, n) pp("%d %lld\n", ans[i].x, ans[i].y);
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址