bzoj 1264: [AHOI2006]基因匹配Match (树状数组优化dp)

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1264

思路: n大小为20000*5,而一般的dp求最长公共子序列复杂度是 n*n的,所以我们必须优化。

题目说了一个数会出现5次,那么我们可以预处理得到 第一个序列a[]每个数字分别在哪些位置,

因为求LCS的状态转移方程中当 s1[i-1] == s2[j-1]时,dp[i][j] = dp[i-1][j-1] + 1;只有当两个点相同时

值才会+1,我们可以对第二个序列b[]遍历一遍,对于b[i]我们可以找到它在a[]上的5个位置,这5个

位置的dp[pos]都可以被更新,状态转移方程为: dp[pos] = max(p[1] - p[pos-1]) + 1, 对于dp[1] - dp[pos],

这段区间的最大值,我们直接用树状数组维护就好了,时间复杂度为 O(n*logn)

实现代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int M = 2e5+10;
int a[M][7],c[M],dp[M],n;

void update(int x,int p){
     while(x <= n*5){
     c[x] = max(c[x],p);
     x += (x&-x);
     }
}

int getsum(int x){
    int ans = 0;
    while(x){
        ans = max(ans,c[x]);
        x -= (x&-x);
    }
    return ans;
}

int main()
{
    int x;
    cin>>n;
    for(int i = 1;i <= n*5;i ++){
        cin>>x;
        a[x][++a[x][0]] = i;
    }
    for(int i = 1;i <= n*5;i ++){
        cin>>x;
        for(int j = 5;j >= 1;j --){
            int num = getsum(a[x][j]-1)+1;
            if(num > dp[a[x][j]]) dp[a[x][j]] = num,update(a[x][j],num);
        }
    }
    int ans = 0;
    for(int i = 1;i <= n*5;i ++){
        ans = max(dp[i],ans);
    }
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/kls123/p/10567388.html

时间: 2024-10-29 02:38:13

bzoj 1264: [AHOI2006]基因匹配Match (树状数组优化dp)的相关文章

BZOJ-1264 :[AHOI2006]基因匹配Match(树状数组+DP)

1264: [AHOI2006]基因匹配Match Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 904  Solved: 578[Submit][Status][Discuss] Description 基因匹配(match) 卡卡昨天晚上做梦梦见他和可可来到了另外一个星球,这个星球上生物的DNA序列由无数种碱基排列而成(地球上只有4种),而更奇怪的是,组成DNA序列的每一种碱基在该序列中正好出现5次!这样如果一个DNA序列有N种不同的碱基构成

BZOJ 1264: [AHOI2006]基因匹配Match( LCS )

序列最大长度2w * 5 = 10w, O(n²)的LCS会T.. LCS 只有当a[i] == b[j]时, 才能更新答案, 我们可以记录n个数在第一个序列中出现的5个位置, 然后从左往右扫第二个序列时将第一个序列对应位置的值更新, 用树状数组维护. 时间复杂度O(nlogn) ------------------------------------------------------------------------------------------------- #include<bi

BZOJ 1264 AHOI2006 基因匹配Match 动态规划+树状数组

题目大意:给定n个数和两个长度为n*5的序列,每个数恰好出现5次,求两个序列的LCS n<=20000,序列长度就是10W,朴素的O(n^2)一定会超时 所以我们考虑LCS的一些性质 LCS的决策+1的条件是a[i]==b[j] 于是我们记录a序列中每个数的5个位置 扫一下b[i] 对于每个b[i]找到b[i]在a中的5个位置 这5个位置的每个f[pos]值都可以被b[i]更新 于是找到f[1]到f[pos-1]的最大值+1 更新f[pos]即可 这个用树状数组维护 时间复杂度O(nlogn)

BZOJ 1264 [AHOI2006]基因匹配Match

有一定思维难度的题目..看了mps大爷的题解才会做(%%% mps) 考虑暴力O(n^2)dp的算法,只有当A[i] == B[j]时才会+1.我们可以利用这个性质,记录下每个数在A[i]中的5个位置.然后从前往后扫描B,顺便转移.转移时要维护前缀max,这个可以用树状数组随意维护一下.时间复杂度是O(nlogn)的 具体看代码 1 //F[i]表示B与A中前i个数的LCS长度 2 3 #include <cstdio> 4 #include <algorithm> 5 6 usi

HDU 6240 Server(2017 CCPC哈尔滨站 K题,01分数规划 + 树状数组优化DP)

题目链接  2017 CCPC Harbin Problem K 题意  给定若干物品,每个物品可以覆盖一个区间.现在要覆盖区间$[1, t]$. 求选出来的物品的$\frac{∑a_{i}}{∑b_{i}}$的最小值. 首先二分答案,那么每个物品的权值就变成了$x * b_{i} - a_{i}$ 在判断的时候先把那些权值为正的物品全部选出来, 然后记录一下从$1$开始可以覆盖到的最右端点的位置. 接下来开始DP,按照区间的端点升序排序(左端点第一关键字,右端点第二关键字) 问题转化为能否用剩

HDU 6447 - YJJ&#39;s Salesman - [树状数组优化DP][2018CCPC网络选拔赛第10题]

Problem DescriptionYJJ is a salesman who has traveled through western country. YJJ is always on journey. Either is he at the destination, or on the way to destination.One day, he is going to travel from city A to southeastern city B. Let us assume th

LUOGU P2344 奶牛抗议 (树状数组优化dp)

传送门 解题思路 树状数组优化dp,f[i]表示前i个奶牛的分组的个数,那么很容易得出$f[i]=\sum\limits_{1\leq j\leq i}f[j-1]*(sum[i]\ge sum[j-1])$,但是这样的时间复杂度是$O(n^2)?$,所以考虑优化,发现必须满足$sum[i]\ge sum[j-1]?$才能进行转移,那么直接离散化后用树状数组维护一个前缀和即可. #include<iostream> #include<cstdio> #include<cstr

bzoj 4990 [USACO17FEB] Why Did the Cow Cross the Road II P (树状数组优化DP)

题目大意:给你两个序列,你可以两个序列的点之间连边 要求:1.只能在点权差值不大于4的点之间连边 2.边和边不能相交 3.每个点只能连一次 设表示第一个序列进行到 i,第二个序列进行到 j,最多连的边数,容易得到方程: 不连边: 连边: 实际是这样的,每个位置如果想连边,就要从能连边的位置之前找最大值,即 直接转移不可取,由于最多只从9个位置转移,我们可以缩减一维,用记录b序列进行到位置 j 的最大连边数,再用树状数组维护的最大前缀和方便转移 1 #include <bits/stdc++.h>

bzoj3594: [Scoi2014]方伯伯的玉米田--树状数组优化DP

题目大意:对于一个序列,可以k次选任意一个区间权值+1,求最长不下降子序列最长能为多少 其实我根本没想到可以用DP做 f[i][j]表示前i棵,操作j次,最长子序列长度 p[x][y]表示操作x次后,最高玉米为y时的最长子序列长度 那么以n棵玉米分阶段,对于每个阶段 f[i][j]=max{p[k][l]}+1,  其中k=1 to j , l=1 to a[i]+j 然后用树状数组维护p[][]的最大值 1 #include<stdio.h> 2 #include<string.h&g