題目
https://loj.ac/problem/3217
思路
狀壓dp
考慮確定了前i個,記錄後面n-i個點之間的間隔裏已選的數
發現狀態不是很大,於是又hash存一下就行
代碼
#include<bits/stdc++.h>
#define N 41
#define M 3200001
#define ll long long
using namespace std;
struct sth {
long long a;
int b;
} dp[2][M], as[N];
sth operator+(sth a, sth b) {
if (a.b < b.b)
return a;
if (a.b > b.b)
return b;
return (sth){ a.a + b.a, a.b };
}
vector<ll> vl[2];
int n, p[N], ct[N];
int md = 4194303;
struct hs {
ll v[4200001];
int head[4200001], nx[4200001], k[4200001], cnt;
hs() { cnt = 0; }
void add(ll x, int y) {
k[++cnt] = y;
v[cnt] = x;
nx[cnt] = head[x & md];
head[x & md] = cnt;
}
void clear() {
cnt = 0;
memset(head, 0, sizeof(head));
}
int finds(ll x) {
for (int i = head[x & md]; i; i = nx[i])
if (v[i] == x)
return k[i];
return 0;
}
} t[2];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &p[i]);
ct[0] = 1;
dp[0][1] = (sth){ 1ll, 0 };
t[0].add(0, 1);
vl[0].push_back(0);
vl[0].push_back(0);
for (int i = 0; i < n; i++) {
int su = 0;
vl[~i & 1].push_back(0);
for (int j = 1; j <= ct[i]; j++) dp[~i & 1][j] = (sth){ 0, 233333 };
for (int j = i + 2; j <= n; j++)
if (p[j] < p[i + 1])
su++;
for (int j = 1; j <= ct[i]; j++) {
ll v = vl[i & 1][j], v2 = v, v3, v4;
int ct1 = 0, ct2 = 0, ct3 = 0, ct4 = 0;
while (v2) ct1 += v2 & 1, v2 >>= 1;
v2 = v;
while (ct2 < su || (v2 & 1)) ct2 += ~v2 & 1, ct4 += v2 & 1, v2 >>= 1, ct3++;
v3 = (v & ((1ll << ct3) - 1)) | (v >> (ct3 + 1) << ct3);
v4 = v | (1ll << ct3);
int r1 = t[~i & 1].finds(v3), r2 = t[~i & 1].finds(v4);
if (!r1)
r1 = ++ct[i + 1], t[~i & 1].add(v3, ct[i + 1]), vl[~i & 1].push_back(v3),
dp[~i & 1][ct[i + 1]] = (sth){ 0, 233333 };
if (!r2)
r2 = ++ct[i + 1], t[~i & 1].add(v4, ct[i + 1]), vl[~i & 1].push_back(v4),
dp[~i & 1][ct[i + 1]] = (sth){ 0, 233333 };
dp[~i & 1][r1] = dp[~i & 1][r1] + dp[i & 1][j];
dp[~i & 1][r2] = dp[~i & 1][r2] + (sth){ dp[i & 1][j].a, dp[i & 1][j].b + ct1 - ct4 };
}
t[i & 1].clear();
vl[i & 1].clear();
vector<ll>().swap(vl[i & 1]);
}
for (int i = 0; i <= n; i++) as[i] = (sth){ 0, 233333 };
for (int i = 1; i <= ct[n]; i++) {
ll v1 = vl[n & 1][i];
int ct = 0;
while (v1) ct += v1 & 1, v1 >>= 1;
as[ct] = as[ct] + dp[n & 1][i];
}
for (int i = 1; i <= n; i++) printf("%d %lld\n", as[i].b, as[i].a);
}