洛谷 P2516 [HAOI2010]最长公共子序列 (LCS+滚动数组)

题目:

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5005,mod=100000000;
int d1[2][N],d2[2][N];//滚动数组,最长公共子序列长度,最长公共子序列个数
char s1[N],s2[N]; 
int main()
{
    
    
	scanf("%s",s1+1);scanf("%s",s2+1);
	int n=strlen(s1+1)-1,m=strlen(s2+1)-1;
	int now=1,pre=0;//分别表示当前状态和上一个状态
	for(int i=0;i<=m;i++){
    
    
		//确定边界 
		//当一条串不选取字符时,最长公共子串数是1 
		d2[0][i]=1;
		d2[1][0]=1;
	}
	for(int i=1;i<=n;i++){
    
    
		for(int j=1;j<=m;j++){
    
    
			//pre为下标的数组就相当于i-1状态 
			//d1[pre][j]相当于d1[i-1][j],d1[now][j-1]相当于d1[i][j-1]
			d1[now][j]=max(d1[pre][j],d1[now][j-1]);
			d2[now][j]=0;
			if(s1[i]==s2[j]) d1[now][j]=max(d1[now][j],d1[pre][j-1]+1);
			 /*以下四种情况进行讨论
			 1、s1[i]=s2[j]且d1[i][j]=d1[i-1][j-1]+1
			 2、d1[i-1][j]=d1[i][j]
			 3、d1[i][j-1]=d1[i][j]
			 4、d1[i-1][j-1]=d1[i][j]
			*/
			if(s1[i]==s2[j]&&d1[now][j]==d1[pre][j-1]+1) d2[now][j]+=d2[pre][j-1];//最长公共子序列变长了
			if(d1[now][j]==d1[pre][j]) d2[now][j]+=d2[pre][j];//从i-1到i,最长公共子序列的长度没有变化
			if(d1[now][j-1]==d1[now][j]) d2[now][j]+=d2[now][j-1];//从j-1到j,最长公共子序列的长度没有变化
			if(d1[pre][j-1]==d1[now][j]) d2[now][j]-=d2[pre][j-1];//容斥原理,减掉重复的情况
			d2[now][j]%=mod; 
		}
		now=pre,pre^=1;//滚动数组,now和pre在0和1之间交换 
	} 
	cout<<d1[pre][m]<<endl<<d2[pre][m];
	
}

总结:

这题的第一问是标准的LCS模板题

第二问的关键在于对于四种情况的分析,既不能多算也不能少算

另外滚动数组也很重要,不然百分百超内存

总体做下来,第一问很快就解决了,第二问一开始没有思路,后面参考了大佬的题解才知道了解题方法


猜你喜欢

转载自blog.csdn.net/Lzhzl211/article/details/114677883