P1439 【模板】最长公共子序列

首先考虑动态规划,a[i]==b[j],f[i][j]=f[i-1][j-1]+1,否则 f[i][j]=max(f[i-1][j],f[i][j-1]);然后看了一眼数据范围,被卡的实施的,然后考虑优化,看到题目是一个排列于是不要考虑重复的问题,于是只在b里看,如果b[i]在a中的位置,小于我们维护的最长的就不行,否则的话直接加入我们维护的最长子序列的长度。就像贪心+二分找最长上升子序列一样。

点击查看代码
#include <iostream>
#include <stack>
#include <cmath>
#include <algorithm>
#include <set>
#include <vector>
#include <climits>
#include <string.h>
#include <map>
#include <queue>
#include <list>
#include <cmath>
#include <iomanip> 
#define int long long 
#define ios ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define lc u<<1
#define rc u<<1|1
#define gcd __gcd
#define double long double
#define endl "\n"
#define INF LLONG_MAX
#define mod  1000000007
#define N 100005
const double PI = 3.14159265358979323846;
using namespace std;
int n, a[N], b[N],f[N],ma[N];//ma数组记录每个元素在a中的位置
signed main()
{
    ios;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        ma[a[i]] = i;
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> b[i];
        f[i] = INF;
    }
    int len = 0;//当前最长子序列的长度
    f[0] = 0;//开始状态
    for (int i = 1; i <= n; i++)
    {
        int l = 0, r = len, mid;
        if (ma[b[i]] > f[len])f[++len] = ma[b[i]];//出现的位置在后面
        else
        {
            while (l < r)//找到第一个大于等于ma[b[i]]的位置
            {
                mid = l + r >> 1;
                if (f[mid] > ma[b[i]]) r = mid;
                else l = mid + 1;
            }
        }
        f[l] = min(ma[b[i]], f[l]);
    }
    cout << len << endl;
    return 0;
}
posted @ 2024-10-19 10:09  Aloongyy  阅读(36)  评论(0)    收藏  举报