CF463D Gargari and Permutations

CF463D 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 found kk permutations. Each of them consists of numbers 1,2,...,n1,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

输入格式

The first line contains two integers nn and kk (1<=n<=1000; 2<=k<=5) . Each of the next kk lines contains integers 1,2,...,n1,2,...,n in some order — description of the current permutation.

输出格式

Print the length of the longest common subsequence.

题意翻译

题目描述

给你k个长度为n的排列,求这些排列的最长公共子序列的长度

输入格式

第一行包含n(1<=n<=1000)和k(2<=k<=5)。 后面的k行分别表示k个排列。

输出格式

输出最长公共子序列的长度

说明

第一个测试样本的答案是子序列[1,2,3]。

输入输出样例

输入 #1复制

输出 #1复制

说明/提示

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

题解:

2019.11.1模拟赛T2 20分场

首先阐明一个重要至极的性质:这个东西是排列,并不是数列。

排列数列的区别就是,排列就是\(1-n\)这些数变换顺序,而数列是\(n\)个你也不知道是多大的数变换顺序。

那么我们就会发现这样的一个性质:对于每一个排列,是否能为最大公共子序列长度做出贡献的决定因素仅是这些数的排列顺序。

回顾一下我们最长公共子序列的模板,为了保证转移的正确性,我们采取的是对于每一个数,遍历它之前的所有的数这种方法,是\(O(n^2)\)的。那么对于这道题,我们只需要记录下来每个数在每行中出现的位置。那么我们发现:我们只看第一个排列,枚举这个排列中每个数在所有行上的位置。假如相对位置都一样,即对于所有的数列,都有\(pos[i]\ge pos[j]\),那么它就可以为答案做出贡献。

所以我们用一个\(flag\)判断是否需要转移。最后遍历一次统计一下答案即可。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1010;
int n,m,ans;
int a[20][maxn],pos[20][maxn],dp[maxn];
//a数组存原数,pos数组存位置
//dp[i]表示以i结尾的最长公共子序列长度
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&a[i][j]);
            pos[i][a[i][j]]=j;
        }
    for(int i=1;i<=n;i++)
        dp[i]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
        {
            int x=a[1][i];
            int y=a[1][j];
            int flag=1;
            for(int t=2;t<=m && flag;t++)
                if(pos[t][x]<pos[t][y])
                    flag=0;
            if(flag)
                dp[x]=max(dp[x],dp[y]+1);
        }
    ans=0;
    for(int i=1;i<=n;i++)
        ans=max(ans,dp[i]);
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fusiwei/p/11777306.html