最长公共子序列

也许更好的阅读体验

\(\mathcal{Description}\)

对于一个长度为\(A\)的正整数序列\(B\),定义其一个长度为\(C\left(0 < C \leq A\right)\)的非空子
序列为一个长度为\(C\)的下标序列\(P_{1 ... C}\),满足\(1 \leq P_1 < P_2 < ⋯ < P_C \leq A\)
子序列本身就是按照顺序把对应的元素拿出来\(:B_{P_1},B_{P_2}, ... B_{P_C}\)
给定一个长度为\(N\)的正整数序列\(S\)和一个长度为\(M\)的正整数序列\(T\),同时再给
定一个有\(K\)条边的有向图\(G\)。请你求出它们有多少个公共子序列,满足把子序列
拿出来之后,对于任意相邻两个元素\((a, b)\),满足在\(G\)中存在一条有向边\(< a, b >\)
这里子序列不同,定义为下标位置不同(即序列\(P\)不同)。

\(1 ≤ N, M ≤ 3000 ,0 ≤ K ≤ 10^6 ,∀1 ≤ i ≤ N, 1 ≤ S[i] ≤ 10^9, ∀1 ≤ i ≤ M, 1 ≤ T[i] ≤ 10^9, 1 ≤ s, t ≤ 10^9\)

\(\mathcal{Solution}\)

考虑和求最长公共子序列类似的dp方式,先固定一个公共子序列的末端为ai,然后枚举bj 找到bj时将前面允许的合法转移加上即可
考试时脑子抽了,打了个树状数组,枚举边,但是ai被固定只需用邻接表查看即可

\(\mathcal{Code}\)

/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年10月09日 星期三 08时13分00秒
*******************************/
#include <cstdio>
#include <fstream>
#include <algorithm>
using namespace std;
const int maxn = 6005;
const int mod = 1000000007;
//{{{cin
struct IO{
	template<typename T>
	IO & operator>>(T&res){
		res=0;
		bool flag=false;
		char ch;
		while((ch=getchar())>'9'||ch<'0')	flag|=ch=='-';
		while(ch>='0'&&ch<='9')	res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
		if (flag)	res=~res+1;
		return *this;
	}
}cin;
//}}}
int n,m,k,tot,ans;
int a[maxn],b[maxn],c[maxn],f[maxn];
bool mp[maxn][maxn];
inline void add (int &x,int y){	x=(x+y)%mod;}
inline int lsh (int x) { return lower_bound(c+1,c+tot+1,x)-c; }
int main()
{
	/*
	 * 考虑和求最长公共子序列类似的dp方式,先固定一个公共子序列的末端为ai,然后枚举bj 找到bj时将前面允许的合法转移加上即可
	 * 考试时脑子抽了,打了个树状数组,枚举边,但是ai被固定只需用邻接表查看即可
	 */
	cin>>n>>m>>k;
	for (int i=1;i<=n;++i)	cin>>a[i],c[++tot]=a[i];
	for (int i=1;i<=m;++i)	cin>>b[i],c[++tot]=b[i];

	sort(c+1,c+tot+1);
	tot=unique(c+1,c+tot+1)-c-1;
	for (int i=1;i<=n;++i)	a[i]=lsh(a[i]);
	for (int i=1;i<=m;++i)	b[i]=lsh(b[i]);

	for (int i=1;i<=k;++i){
		int u,v,a,b;
		cin>>a>>b;
		u=lsh(a),v=lsh(b);
		if (u<=tot&&v<=tot&&c[u]==a&&c[v]==b)	mp[u][v]=true;
	}

	for (int i=1;i<=n;++i){
		int s=1;
		for (int j=1;j<=m;++j){
			int t=f[j];
			if (a[i]==b[j])	add(f[j],s),add(ans,s);
			if (mp[b[j]][a[i]])	add(s,t);
		}
	}
	printf("%d\n",ans);
	return 0;
}

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

posted @ 2019-10-09 19:15  Morning_Glory  阅读(490)  评论(0编辑  收藏  举报
//