这是第一次写博客,参加学校的acm已经有一年的时间了,现在才开始写,说实话有点晚,但再不写就更晚了,现在在做最长子序列方面的题,找了一道比较经典的题来举例。
题目链接:https://www.luogu.org/problemnew/show/P1020
首先讲题目意思,第一问求最长不上升子序列,第二问求最长上升子序列,说实话第二问一开始我没看出是求上升子序列的,看了别的大佬的题解才发现用上升子序列。
第一种,简单的动态规划,O(n^2)的算法
#include <map>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int a[100005],dp1[100005],dp2[100005];
int main()
{
int n=0;
while(~scanf("%d",&a[++n]))
continue;
n--;
int ans1=0,ans2=0;
for(int i=n; i>0; i--)
{
dp1[i]=1;
for(int j=i+1; j<=n; j++)
{
if(a[j]<=a[i])
{
dp1[i]=max(dp1[i],dp1[j]+1);
}
}
ans1=max(ans1,dp1[i]);
}
for(int i=1; i<=n; i++)
{
dp2[i]=1;
for(int j=1;j<i;j++)
{
if(a[j]<a[i])
{
dp2[i]=max(dp2[i],dp2[j]+1);
}
}
ans2=max(ans2,dp2[i]);
}
printf("%d\n",ans1);
printf("%d\n",ans2);
return 0;
}
第二种,用了二分法,O(n*logn)的算法,我是借鉴了大佬的思想
大佬博客链接:https://www.cnblogs.com/wxjor/p/5524447.html
代码如下:
#include <map>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int a[100005],dp[100005];
int main()
{
int n=0;
while(~scanf("%d",&a[++n]))
continue;
n--;
int ans1=0,ans2=0;
dp[0]=INF;
for(int i=1; i<=n; i++)
{
if(dp[ans1]>=a[i])
{
ans1++;
dp[ans1]=a[i];
}
else
{
int l=0,r=ans1;
while(l<r)
{
int mid=(l+r)/2;
if(dp[mid]<a[i])
{
r=mid;
}
else
{
l=mid+1;
}
}
if(l!=0)
dp[l]=a[i];
}
}
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
if(dp[ans2]<a[i])
{
ans2++;
dp[ans2]=a[i];
}
else
{
int l=0,r=ans2;
while(l<r)
{
int mid=(l+r)/2;
if(dp[mid]<a[i])
{
l=mid+1;
}
else
{
r=mid;
}
}
dp[l]=a[i];
}
}
printf("%d\n",ans1);
printf("%d\n",ans2);
return 0;
}
第三种,我只能说stl真好啊,也是O(n*logn)的算法,同样借鉴大佬
这里最重要的是两个函数lower_bound和upper_bound,自己去查,解决最长上升子序列的好东西
其实思路和上一种方法一样,只是好写并且短
代码如下:
#include <map>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int a[100005],dp1[100005],dp2[100005];
struct cmp
{
bool operator()(int x,int y)
{
return x>y;
}
};
int main()
{
int n=0;
while(~scanf("%d",&a[++n]))
continue;
n--;
int ans1=1,ans2=1;
dp1[1]=dp2[1]=a[1];
for(int i=2; i<=n; i++)
{
if(dp1[ans1]>=a[i])
dp1[++ans1]=a[i];
else
dp1[upper_bound(dp1+1,dp1+ans1+1,a[i],cmp())-dp1]=a[i];
if(dp2[ans2]<a[i])
dp2[++ans2]=a[i];
else
dp2[lower_bound(dp2+1,dp2+ans2+1,a[i])-dp2]=a[i];
}
printf("%d\n",ans1);
printf("%d\n",ans2);
return 0;
}
第四种,用树状数组写,O(n*logn)的算法
这种方法我就不放代码了,自己写吧