「PA 2019」Desant

題目

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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章