LCS ( O(n*m) )
最长公共子序列
dp[i][j]表示a数组前i个,b数组前j个的最长公共子序列长度
状态转移方程:
a[i]!=b[j]
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
a[i]==b[j]
dp[i][j]=dp[i-1][j-1]+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i]==b[j])
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
LIS ( O(nlogn )
最长严格递增子序列
//lower_bound(begin,end,num)在从小到大的数组中,返回第一个大于等于num的数的地址
fill(lis,lis+110,INT_MAX);
for(int i=0;i<n;i++)
{
cin>>x;
*lower_bound(lis,lis+110,x)=x;
}
cout<<lower_bound(lis,lis+110,INT_MAX)-lis<<endl;
打印路径:当在lis中填入x时,前一位一定是小于且先于x的,那么pre[x]=lis[x的位置-1]
LCIS ( O(n*m)
最长公共上升子序列
a[]={1,4,2,5,-12}
b[]={-12,1,2,4}
dp[i][j]表示 a的前i个和b的前j个数,以b[j]为结尾 的lcis
状态转移方程:
当a[i]!=b[j],
a的前i个和b的前j个数,以b[j]为结尾的lcis=a的前i-1个和b的前j个数,以b[j]为结尾的lcis① a[i] != b[j], dp[i][j] = dp[i-1][j]
当a[i]==b[j],
a的前i个和b的前j个数,以b[j]为结尾的lcis=a的前i-1个和b的前k个数(1<=k<j,dp[i-1][k]最大且b[k]<b[j]),以b[k]为结尾的lcis
② a[i] == b[j], dp[i][j] = max(dp[i-1][k]+1) (1 <= k < j && b[j] > b[k])
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
{
int max_=0;
for(int j=1;j<=m;j++)
{
if(a[i]!=b[j])
dp[i][j]=dp[i-1][j];
else
dp[i][j]=max_+1;
if(a[i]>b[j])
max_=max(max_,dp[i][j]);
}
}
最大连续子序列
int head=0,rehead=0,rear=0,maxn=-1,res=0;
for(int i=0;i<n;i++)
{
res+=a[i];//res为当前的连续子序列和
if(res<0) //不可能是最终答案
{
res=0;
rehead=i+1;
}
else
{
if(maxn<res)//可能是最终答案,更新数据
{
maxn=res;
head=rehead;//rebegin为最近一次更新的起始端
rear=i;
}
}
}
\\前缀和
#include <bits/stdc++.h>
using namespace std;
int a[100010],sum[100010];
const int INF=0x3f3f3f;
int main()
{
int t,n;
scanf("%d",&t);
for(int k=1;k<=t;k++)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
int min_val=INF,ans=-INF,l,rl,r;
for(int i=1;i<=n;i++)
{
if(min_val>sum[i-1])
{
min_val=sum[i-1];
rl=i;
}
if(ans<sum[i]-min_val)
{
ans=sum[i]-min_val;
l=rl,r=i;
}
}
printf("Case %d:\n%d %d %d\n",k,ans,l,r);
if(k<t) putchar('\n');
}
return 0;
}
最大m字段
数组a[]={-4,5,6,-2,3,1}
dp[i][j]表示将 数组前j个数分成i段,并且最后一段以第j个数结尾 的最大和
状态转移方程:
拼接a[j]到第i段末尾
dp[i][j]=dp[i][j-1]+a[j];
a[j]单独作为第i段开头
dp[i][j]=dp[i-1][k]+a[j], i-1<=k<j;
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
{
int max_=dp[i-1][i-1];
dp[i][i]=dp[i-1][i-1]+a[i];
for(int j=i+1;j<=n;j++)
{
max_=max(max_,dp[i-1][j-1]);
dp[i][j]=max(max_,dp[i][j-1])+a[j];
}
}