[Nowcoder 2018ACM多校第九场G] Longest Common Subsequence

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013578420/article/details/81783129

题目大意:
给你4个长度为n的数组, 数组中每个元素都在1~n内, 且在同一个数组中每个元素最多重复2次, 求这4个数组的最长公共子序列。 ( n 10000 )

题目思路:
考虑dp[i][j][k][l], 表示四个数组匹配到了相应位置的答案, 只有当i,j, k, l四个位置的值完全相同时才会产生加1的贡献。 考虑到每个值最多重复2次, 实质上状态数是8n级别的。 本质是求一个4位的最长偏序。
考虑使用kd-tree, 现将前3维做成节点存在kd-tree中, 按照剩下一维的顺序枚举, 每次处理完包含i的四元组在kd-tree中的询问后, 再更新kd-tree中的相应节点。 在kd-tree的询问过程中使用各种优化剪枝。

Code:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <cmath>
#include <vector>

#define ll long long
#define db double
#define fi first
#define se second
#define pi pair<int, int >
#define ls (x << 1)
#define rs ((x << 1) | 1)
#define mid ((l + r) >> 1)
#define mp(x, y) make_pair((x), (y))
#define pb push_back

using namespace std;
const int N = (int)1e4 + 10;

int a[N], b[N * 8];
vector<int > pos[3][N], vec[N]; int n;
struct Poi{
    int d[3], val, id;
    int mxd[3], mnd[3], max_val;
    Poi(){}
    Poi(int a, int b, int c, int i){
        mxd[0] = mnd[0] = d[0] = a;
        mxd[1] = mnd[1] = d[1] = b;
        mxd[2] = mnd[2] = d[2] = c;
        id = i;
    }
}poi[N * 8]; int tot;

int rt, fa[N * 8], ch[N * 8][2];
int H;
bool cmp(const Poi &x, const Poi &y){
    for (int i = 0; i < 3; i ++){
        int j = (i + H) % 3;
        if (x.d[j] != y.d[j]) return x.d[j] < y.d[j];
    }
    return 0;
}
void update(int x, int y){
    for (int j = 0; j < 3; j ++){
        poi[x].mxd[j] = max(poi[x].mxd[j], poi[y].mxd[j]);
        poi[x].mnd[j] = min(poi[x].mnd[j], poi[y].mnd[j]);
    }
}
int build(int l, int r, int k, int pre){
    H = k;
    fa[mid] = pre;
    nth_element(poi + l, poi + mid, poi + r + 1, cmp);
    if (l != mid) update(mid, ch[mid][0] = build(l, mid - 1, k + 1, mid));
    if (mid != r) update(mid, ch[mid][1] = build(mid + 1, r, k + 1, mid));
    //printf("%d %d %d\n", mid, ch[mid][0], ch[mid][1]);
    return mid;
}

int qd[3], res;
bool in(int x){
    for (int j = 0; j < 3; j ++)
        if (qd[j] < poi[x].mxd[j]) return 0;
    return 1;
}
bool out(int x){
    for (int j = 0; j < 3; j ++)
        if (qd[j] < poi[x].mnd[j]) return 1;
    return 0;
}
bool chk(int x){
    for (int j = 0; j < 3; j ++)
        if (qd[j] < poi[x].d[j]) return 0;
    return 1;
}
void query(int x){
    if (!x) return;
    if (res >= poi[x].max_val) return;
    if (out(x)) return;

    if (in(x)) res = max(res, poi[x].max_val);
    else {
        if (chk(x)) res = max(res, poi[x].val);
        query(ch[x][0]), query(ch[x][1]);
    }
}
void modf(int x, int v){
    poi[x].val = max(poi[x].val, v);
    for (int p = x; p; p = fa[p]) poi[p].max_val = max(poi[p].max_val, poi[x].val);
}

int main(){

    scanf("%d", &n);
    for (int i = 0; i < 4; i ++)
        for (int j = 1, x; j <= n; j ++){
            scanf("%d", &x);
            if (i < 3) pos[i][x].pb(j);
            else a[j] = x;
        }

    for (int x = 1; x <= n; x ++)
        for (int i = 0; i < pos[0][x].size(); i ++)
            for (int j = 0; j < pos[1][x].size(); j ++)
                for (int k = 0; k < pos[2][x].size(); k ++){
                    ++ tot;
                    poi[tot] = Poi(pos[0][x][i], pos[1][x][j], pos[2][x][k], tot);
                    vec[x].pb(tot);
                }

    rt = build(1, tot, 0, 0);
    for (int i = 1; i <= tot; i ++) b[poi[i].id] = i;

    for (int i = 1; i <= n; i ++){
        vector<pair<int, int> > dp;

        for (int j = 0; j < vec[a[i]].size(); j ++){
            int nd = b[vec[a[i]][j]];
            res = 0;
            for (int k = 0; k < 3; k ++) qd[k] = poi[nd].d[k] - 1;
            query(rt);
            dp.pb(mp(nd, res + 1));

            /*if (i == 2 && qd[0] == 1 && qd[1] == 1 && qd[2] == 2){
                printf("%d\n", res);
                }*/
        }

        for (int j = 0; j < dp.size(); j ++){
            modf(dp[j].fi, dp[j].se);

        }

    }

    printf("%d\n", poi[rt].max_val);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013578420/article/details/81783129