大数据LIS (贪心+二分优化/树状数组优化)
Posted just afw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大数据LIS (贪心+二分优化/树状数组优化)相关的知识,希望对你有一定的参考价值。
题目描述(原线性dp)
给出 1,2,…,n 的两个排列 P1 和 P2 ,求它们的最长公共子序列。
输入格式
第一行是一个数 n。
接下来两行,每行为 n 个数,为自然数 1,2,…,n 的一个排列。
输出格式
一个数,即最长公共子序列的长度。
输入输出样例
输入 #1
5 3 2 1 4 5 1 2 3 4 5
输出 #1
3
说明/提示
- 对于 50%50% 的数据, n≤103;
- 对于 100%100% 的数据, n≤105。
思路:
两个序列求最长公共子序列,根据题意,两个序列都是1-n的全排列,我们可以利用map进行重排,把第一个序列改成上升序列,那么原问题就转化为了求序列的最长上升子序列
贪心+二分优化:
我们枚举map重排后的新数列,维护一个答案数组是上升子序列,如果当前元素大于答案数组最后一个元素,直接加进去答案数组
否则,在答案数组里找见第一个大于当前元素的元素,将其修改为当前元素
因为如果要这个元素构造出的新数列比没有这个元素的答案数列长,那么这个元素之前的元素和答案数列前面的元素相同,后面的与答案数列无关,直接替换掉第一个大于它的元素即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
int main()
cin>>n;
vector<int>a(n+1);
map<int,int>m;
for(int i=1;i<=n;i++)
int t;
cin>>t;
m[t]=i; //map重排
for(int i=1;i<=n;i++)
int t;
cin>>t;
a[i]=m[t];
vector<int>ans;
ans.push_back(a[1]);
for(int i=2;i<=n;i++)
if(a[i]>ans[ans.size()-1])ans.push_back(a[i]); //添加至最长递增子序列末端
else
int t=upper_bound(ans.begin(),ans.end(),a[i])-ans.begin(); //找第一个大于的数
ans[t]=a[i]; //更改为a[i]
cout<<ans.size();
return 0;
树状数组优化
之前思路一样,然后利用树状数组储存当前元素为 i 时的最大的序列长度
每次枚举新数列,修改大于这个数的 f [ i ] 为当前数列的长度+1
用当前数列长度更新答案即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
int f[100005]; //树状数组 f[i] 记录当前元素为i时LIS序列的元素个数
int query(int x) //查询小于等于x的序列个数
int ans=0;
while(x)
ans=max(ans,f[x]);
x-=(x&(-x));
return ans;
void modify(int x,int y)
while(x<100005)
f[x]=max(f[x],y);
x+=x&(-x);
int main()
cin>>n;
vector<int>a(n+1);
map<int,int>m; //映射处理,使数组1变成上升序列
for(int i=1;i<=n;i++)
int t;
cin>>t;
m[t]=i;
for(int i=1;i<=n;i++) //求数组2的LIS
int t;
cin>>t;
a[i]=m[t];
int ans=0;
for(int i=1;i<=n;i++)
modify(a[i],query(a[i])+1); //大于等于a[i]的数存的序列长度为当前长度+1
ans=max(ans,query(a[i])); //查询小于等于当前值的序列长度
cout<<ans;
return 0;
HDU - 5542 The Battle of Chibi(LIS+树状数组优化)
The Battle of Chibi
So there is only one way left for Yu Zhou, send someone to fake surrender Cao Cao. Gai Huang was selected for this important mission. However, Cao Cao was not easy to believe others, so Gai Huang must leak some important information to Cao Cao before surrendering.
Yu Zhou discussed with Gai Huang and worked out NN information to be leaked, in happening order. Each of the information was estimated to has aiai value in Cao Cao‘s opinion.
Actually, if you leak information with strict increasing value could accelerate making Cao Cao believe you. So Gai Huang decided to leak exact MM information with strict increasing value in happening order. In other words, Gai Huang will not change the order of the NN information and just select MM of them. Find out how many ways Gai Huang could do this.
InputThe first line of the input gives the number of test cases, T(1≤100)T(1≤100). TT test cases follow.
Each test case begins with two numbers N(1≤N≤103)N(1≤N≤103) and M(1≤M≤N)M(1≤M≤N), indicating the number of information and number of information Gai Huang will select. Then NN numbers in a line, the ithith number ai(1≤ai≤109)ai(1≤ai≤109) indicates the value in Cao Cao‘s opinion of the ithith information in happening order.OutputFor each test case, output one line containing Case #x: y, where xx is the test case number (starting from 1) and yy is the ways Gai Huang can select the information.
The result is too large, and you need to output the result mod by 1000000007(109+7)1000000007(109+7).Sample Input
2 3 2 1 2 3 3 2 3 2 1
Sample Output
Case #1: 3 Case #2: 0
Hint
In the first cases, Gai Huang need to leak 2 information out of 3. He could leak any 2 information as all the information value are in increasing order. In the second cases, Gai Huang has no choice as selecting any 2 information is not in increasing order.
题意:求一个序列中长度为m的最长上升子序列个数。
设dp[i][j]表示以当前位置i结束的长度为j的序列个数。
容易想到O(n^3)的做法。开始想用记忆化搜索将复杂度降低一些,再加上若干剪枝,仍然会T。
考虑到问题涉及小于(大于)某个数的数的和,因此应该想到用树状数组优化。
使用lower_bound将所有数离散化,还要注意在dp的同时更新树状数组,时间复杂度为O(n^2*logn)。
//注释部分为优化前
#include<bits/stdc++.h> #define MAX 1005 #define MOD 1000000007 #define lowbit(x) x&(-x) using namespace std; typedef long long ll; int a[MAX],b[MAX]; int n,m; ll dp[MAX][MAX]; ll sum(int x,int y){ ll ans=0; while(1<=x){ ans+=dp[x][y]; ans%=MOD; x-=lowbit(x); } return ans; } void add(int x,int y,int z){ while(x<=n){ dp[x][y]+=z; dp[x][y]%=MOD; x+=lowbit(x); } } int main() { int tt=0,t,i,j,k; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); for(i=1;i<=n;i++){ scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+n+1); for(i=1;i<=n;i++){ a[i]=lower_bound(b+1,b+n+1,a[i])-b; } memset(dp,0,sizeof(dp)); for(i=1;i<=n;i++){ //dp[i][1]=1; add(a[i],1,1); for(j=2;j<=m;j++){ //dp[i][j]=dp[i-1][j]; //for(k=1;k<i;k++){ // if(a[k]<a[i]){ // dp[i][j]+=dp[k][j-1]; // dp[i][j]%=MOD; // } //} ll temp=sum(a[i]-1,j-1); add(a[i],j,temp); } } //printf("Case #%d: %I64d ",++tt,dp[n][m]); printf("Case #%d: %I64d ",++tt,sum(n,m)); } return 0; }
以上是关于大数据LIS (贪心+二分优化/树状数组优化)的主要内容,如果未能解决你的问题,请参考以下文章
AcWing 3510- 最长公共子序列 - 贪心+二分优化