hdu5791 +codeforces 463D (LCS变形)

探讨了两个序列的公共子序列数量计算方法,并通过具体示例解析了最长公共子序列(LCS)问题的解决思路及其应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Two

                                         Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
                                        Total Submission(s): 670    Accepted Submission(s): 308



Problem Description
Alice gets two sequences A and B. A easy problem comes. How many pair of sequence A' and sequence B' are same. For example, {1,2} and {1,2} are same. {1,2,4} and {1,4,2} are not same. A' is a subsequence of A. B' is a subsequence of B. The subsequnce can be not continuous. For example, {1,1,2} has 7 subsequences {1},{1},{2},{1,1},{1,2},{1,2},{1,1,2}. The answer can be very large. Output the answer mod 1000000007.
 

Input
The input contains multiple test cases.

For each test case, the first line cantains two integers N,M(1N,M1000). The next line contains N integers. The next line followed M integers. All integers are between 1 and 1000.
 

Output
For each test case, output the answer mod 1000000007.
 

Sample Input
3 2 1 2 3 2 1 3 2 1 2 3 1 2
 

Sample Output
2 3
 
          题意:给了两个序列,长度分别是n,m,求公共子序列的个数。

          思路:因为刚做了cf的一道关于lcs的题(也就是下面的一道题),思路和其类似。由于数字范围是0~1000,所以我们可以记录0~1000在B串的每个位置,由于数字可以重复,枚举A串中每个位置的数字及该数字在B串的相应的每个位置,求到当前位置且包含该位置的公共子序列集合的个数。然后把所有情况加起来就是answer。因为拿树状数组维护前缀和,所以复杂度O(n^2log(n)。可能数据比较随机吧,跑了31ms比n^2的还快。

          看了下题解,复杂度比我的优多了,O(n^2)的。表示A中前i个数与B中前j个数构成的公共子序列个数。代码见后面。

                

        

D. Gargari and Permutations

Gargari got bored to play with the bishops and now, after solving the problem about them, he is trying to do math homework. In a math book he have foundk permutations. Each of them consists of numbers1, 2, ..., n in some order. Now he should find the length of the longest common subsequence of these permutations. Can you help Gargari?

You can read about longest common subsequence there: https://en.wikipedia.org/wiki/Longest_common_subsequence_problem

Input

The first line contains two integers n andk(1 ≤ n ≤ 1000; 2 ≤ k ≤ 5). Each of the nextk lines contains integers1, 2, ..., n in some order — description of the current permutation.

Output

Print the length of the longest common subsequence.

Examples
Input
4 3
1 4 2 3
4 1 2 3
1 2 4 3
Output
3
Note

The answer for the first test sample is subsequence [1, 2, 3].


         题意:求k个1~n排列的LCS。

       思路:由于每个数字在1个排列中只出现一次,所以我们可以拿vector记录每个数字在k个排列中出现的位置。然后以其中一个序列为标准,枚举这个序列中每个数字,求以其结尾的LCS,其实就是1~i-1位置数字在每个序列中位置比当前数字在相应序列中位置靠前的最大LCS+1.

详细见代码:

           hdu O(n^2logn):

//最坏O(n^2logn),最好O(n),31ms
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn  = 1e3+10;
const int MOD  = 1e9+7;
int A[1010];
int B[1010];
vector<int>v[1010];
int dp[1010];
inline int lowbit(int a)
{
    return a&(-a);
}
void update(int a,int b)
{
    while(a<maxn)
    {
        dp[a]+=b;
        dp[a]%=MOD;
        a+=lowbit(a);
    }
}
int query(int a)
{
    int ans=0;
    while(a)
    {
        ans=(ans+dp[a])%MOD;
        a-=lowbit(a);
    }
    return ans;
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int i,j;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&A[i]);
        }
        int ans=0;
        for(j=1;j<=m;j++)
        {
            scanf("%d",&B[j]);
            v[B[j]].push_back(j);
        }
       
        memset(dp,0,sizeof dp);
        for(i=1;i<=n;i++)
        {
            for(j=v[A[i]].size()-1;j>=0;j--)
            {
                int tmp=(query(v[A[i]][j]-1)+1)%MOD;
                ans=(ans+tmp)%MOD;
                update(v[A[i]][j],tmp);
            }
        }
        for(i=0;i<maxn;i++)
            v[i].clear();
        printf("%d\n",ans);
    }
    return 0;
}

        hdu O(n^2):

//O(n^2) 140ms
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn  = 1e3+100;
const int MOD = 1e9+7;
int A[maxn];
int B[maxn];
int dp[maxn][maxn];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(dp,0,sizeof dp);
        int i,j;
        for(i=1;i<=n;i++)
            scanf("%d",&A[i]);
        for(i=1;i<=m;i++)
            scanf("%d",&B[i]);
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])%MOD;
                if(A[i]==B[j])
                    dp[i][j]=((dp[i][j]+dp[i-1][j-1])%MOD+1)%MOD;
            }
        }
        printf("%d\n",(dp[n][m]+MOD)%MOD);
    }
    return 0;
}

     cf :

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn = 1e3+100;
int A[7][1010];
int dp[1010];
vector<int>v[1010];
int main()
{
	int n,m;
	int i,j,k;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
		for(j=1;j<=n;j++)
			scanf("%d",&A[i][j]),v[A[i][j]].push_back(j);
	}
	for(i=1;i<=n;i++)
	{
		dp[A[1][i]]=max(1,dp[A[1][i]]);
		for(k=1;k<=n;k++)
		{
			if(k==A[1][i]) continue;
			int u;
			for(u=0;u<m;u++)
			{
				if(v[k][u]>v[A[1][i]][u]) break;
			}
			if(u>=m) dp[A[1][i]]=max(dp[A[1][i]],dp[k]+1);
		}
	}
	int ans=1;
	for(i=1;i<=n;i++)
		ans=max(ans,dp[i]);
	cout<<ans<<endl;
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值