bzoj1264

dp+树状数组

思维僵化怎么办。。。

我们都知道,如果两个序列中所有元素都不相同,那么可以用lis求解,复杂度nlogn,但是这道题不行,每种元素出现了5次。。。然后我一直在想有没有什么解决办法

事实上是这个样子的,考虑二维dp,dp[i][j]=dp[i-1][j-1]+1当且仅当s[i]==t[j],我们把这个看做一个点对(i,j),其实我们就是求一个最长的点对序列满足排序后一个点对在另一个点对左下方,那么这就是一个二维偏序,可以用排序lis解决,由于每种元素只出现5次,所以只有25*n对点对

 
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
struct data {
    int a, b;
    data() {}
    data(int a, int b) : a(a), b(b) {}
    bool friend operator < (const data &a, const data &b) {
        return a.a == b.a ? a.b > b.b : a.a < b.a;
    }
} x[N * 5];
vector<int> v1[N], v2[N];
int n, cnt;
int tree[N];
void update(int x, int d) 
{
    for(; x <= n; x += x & -x) tree[x] = max(tree[x], d);
}
int query(int x)
{
    int ret = 0;
    for(; x; x -= x & -x) ret = max(ret, tree[x]);
    return ret;
}
int main()
{
    scanf("%d", &n);
    n *= 5;
    for(int i = 1, x; i <= n; ++i) scanf("%d", &x), v1[x].push_back(i);
    for(int i = 1, x; i <= n; ++i) scanf("%d", &x), v2[x].push_back(i);
    for(int i = 1; i <= n / 5; ++i)
        for(int j = 0; j < v1[i].size(); ++j)
            for(int k = 0; k < v2[i].size(); ++k) 
                x[++cnt] = data(v1[i][j], v2[i][k]);
    sort(x + 1, x + cnt + 1);           
    for(int i = 1; i <= cnt; ++i)
    {
        int tmp = query(x[i].b - 1) + 1;
        update(x[i].b, tmp);
    }
    printf("%d
", query(n));
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/19992147orz/p/7774683.html