HDU-6412 公共子序列

版权声明:选经典题目,写精品文章. https://blog.csdn.net/nka_kun/article/details/81902421

                                                                                          公共子序列

                           Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)


Problem Description
光羽一点都不喜欢高代,某一次高代课上,光羽特意挑了最后一排的位置,睡着睡着,他忽然想到了这道字符串水题!

度度熊有k(k≥2)个序列s1,s2,..,sk,每个序列的长度均为n,且序列中每个数均是1到n之间某个整数,请问这k个串有多少个长度大于0的**公共子序列**?

**解释**:在每个序列中都选出一些位置,并将这些位置对应的字符**顺次**拼接起来,当它们都相等时,称其为公共子序列。

答案可能很大,请对109+7取模。
 

Input
第一行一个数,表示数据组数T。

每组数据第一行两个数k,n;接下来k行,每行一个长度为n的序列si。

数据组数T=80,分别有20组数据满足k=2,3,4,5。

每组数据均满足1≤n≤1000,**且s1,s2,...,sk中每一个数在1到n之间等概率随机生成!!**

**随机生成!!**

**随机生成!!**

**随机生成!!**
 

Output
每组数据输出一行,每行仅包含一个数,表示公共子序列个数。
 

Sample Input
4
2 3
1 2 1 
2 3 1 
3 3
1 2 3 
2 3 1 
1 2 3 
4 3
3 2 2 
3 1 3 
2 3 1 
3 2 1 
5 3
3 1 3 
3 1 1 
1 2 3 
2 3 3 
1 3 3 
 

Sample Output
4
4
2
8


思路:说是1-n每个数等概率随机生成有什么用呢?其实就是说每个序列都相当于1-n的一个全排列,只是个别数字没有出现,个别数字多出现了几次而已.  那么我们是不是可以从这入手呢?  这里想一下公共子序列的dp求法,不断往后维护前面的公共子序列的长度,直到遇到几个串某个位置(在每个串中位置不一定相同)有相同的字符才+1,那是可能每个数字出现很多次的做法.

现在每个数字近似出现一次,所以我们可以把出现相同字符的位置都预处理出来,做成一个随机组合.然后做个排序,只要某个组合里每一个位置都比其他组合相应串中位置大,就能加上那个的数值,就能枚举出来有多少种公共子序列的可能.

代码:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const int maxn = 1e5+5;

int k,n,cnt;
vector<int> mp[6][1234];
ll dp[maxn];

struct node
{
    int p[6];
    friend bool operator < (node x,node y)
    {
        for(int i = 1;i<= k;i++)
            if(x.p[i]>= y.p[i]) return 0;
        return 1;
    }
} a[maxn],b;

void dfs(int x,int v)
{
    if(x == k+1)
    {
        a[++cnt] = b;
        return ;
    }
    
    int s = mp[x][v].size();
    for(int i = 0;i< s;i++)
    {
        b.p[x] = mp[x][v][i];
        dfs(x+1,v);
    }
    return ;
}

void init()
{
    cnt = 0;
    for(int i = 1;i<= k;i++)
        for(int j = 1;j<= n;j++)
            mp[i][j].clear();
}

bool cmp(node x,node y)
{
    for(int i = 1;i<= k;i++)
        if(x.p[i]!= y.p[i])
            return x.p[i]< y.p[i];
    return 0;
}

int main()
{
    int t;
    cin>>t;
    
    while(t--)
    {
        scanf("%d %d",&k,&n);
        init();
            
        for(int i = 1;i<= k;i++)
        {
            for(int j = 1,x;j<= n;j++)
            {
                scanf("%d",&x);
                mp[i][x].push_back(j);
            }
        }
        
        for(int i = 1;i<= n;i++)
            dfs(1,i);
        
        sort(a+1,a+cnt+1,cmp);
        
        for(int i = 1;i<= cnt;i++) dp[i] = 1;
        for(int i = 1;i<= cnt;i++)
            for(int j = 1;j< i;j++)
                if(a[j]< a[i])
                    (dp[i]+= dp[j])%= mod;
        
        ll ans = 0;
        for(int i = 1;i<= cnt;i++)
            (ans+= dp[i])%= mod;
        printf("%lld\n",ans);
    }
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/nka_kun/article/details/81902421
今日推荐