2017-5-14 湘潭市赛 Longest Common Subsequence 想法题

Longest Common Subsequence
Accepted : 7           Submit : 66
Time Limit : 3000 MS           Memory Limit : 65536 KB

Longest Common Subsequence

Bobo has a sequence A=(a1,a2,…,an) of length n. He would like to know f(0),f(1),f(2) and f(3) where f(k) denotes the number of integer sequences X=(x1,x2,x3) where:

    1≤x1,x2,x3≤m;
    The length of longest common subsequence of A and X is exactly k.

Note:

    u is a subsequence of v if and only if u can be obtained by removing some of the entries from v (possibly none).
    u is common subsequence of v and w if and only if u is subsequence of v and w.

Input

The input contains zero or more test cases and is terminated by end-of-file. For each case,

The first line contains two integers n,m. The second line contains n integers a1,a2,…,an.

    1≤n≤200
    1≤m,a1,a2,…,an≤106
    The number of tests cases does not exceed 10.

Output

For each case, output four integers which denote f(0),f(1),f(2),f(3).
Sample Input

3 3
1 2 2
5 3
1 2 3 2 1

Sample Output

1 14 11 1
0 1 17 9

Note

For the second sample, X=(3,3,3) is the only sequence that the length of longest common subsequence of A and X is 1. Thus, f(1)=1.

Source
XTU OnlineJudge 

/**
题目:Longest Common Subsequence
链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1265
题意:给定序列A,含n个数。和一个数m;
有一个X序列{x1,x2,x3},x1,x2,x3来自[1,m]区间内的数。

设:f(k)表示两个序列的最长公共子序列为k;

求序列X和A满足f(0),f(1),f(2),f(3)的X各有多少种。

思路:f(0)易求。计算出n个数中在m范围内的不同数的数量为cnt,然后计算(m-cnt)^3即可。

对n个数中<=m的数,离散化。

要求f(1),f(2),f(3);
f(3)的X序列内的数一定是n个数中获得。
f(2)的X序列内的数有两种来源,一种是三个数从n个数中获得,然后Longest Common Subsequence为2;
另一种是其中两个是n个数中获得,然后Longest Common Subsequence为2,另外一个是<=m的不包含n个数的数中获得。
f(1)的X序列内的数有三种来源,一种是3个数从n个数中获得,然后Longest Common Subsequence为1;
另一种是两个数从n个数中获得,然后Longest Common Subsequence为1;另外一个是是<=m的不包含n个数的数中获得。
另一种是其中一个是n个数中获得,然后Longest Common Subsequence为1,另外二个是<=m的不包含n个数的数中获得。

设:cnt表示n个数中<=m的数。kind表示n个数中<=m的不同数的种类。m-kind表示不包含n个数的数的种数。

枚举x1,x2,x3全是n个数组成的X序列,所有xi都枚举所有的n个数。

这些序列包含f(3),f(2)第一种来源,f(1)第一种来源的情况数。计算方法:一种是常规的Longest Common Subsequence 的dp求法,但是总时间复杂度为O(N^4);
更好的做法是:预处理next[i][j]表示i这个位置右边第一次出现j这个数的位置。那么可以O(1)判断X序列的Longest Common Subsequence为k。把它们更新到f(k)中。
flag[a[i]][a[j]][a[k]]表示这个序列可以匹配的最大LCS;取最值,最后遍历计算即可。

剩下要求f(2)的第二种来源,f(1)的第二种来源和第三种来源。
f(2)第二种来源:三种可能(x1,x2),(x2,x3),(x1,x3)位置,Longest Common Subsequence为2,另一个位置为m-kind中取。 其实情况数是一样的。f(2) += 3*Q(cnt)*(m-kind);
Q(cnt)表示cnt个数中找到与A序列的Longest Common Subsequence为2的序列数量。暴力枚举两个位置,同上面说的方法。

f(1)第二种来源:三种可能(x1,x2),(x2,x3),(x1,x3)位置,但是Longest Common Subsequence为1;另外一个位置从m-kind中取。 f(1) += 3*P(cnt)*(m-kind);
f(1)第三种来源:三种可能x1,x2,x3位置相同,另外两个位置为m-kind中取。f(1) += 3*kind*(m-kind)*(m-kind);

思考:为什么要用next[i][j]表示i这个位置右边第一次出现j这个数的位置。而不是直接next[i][j]表示j这个数是否在i的右边。
假设: 2 2
那么枚举出来2 2 2. 如果用后者所述定义,那么答案就是3了。实际上只能是2.
*/

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> P;
const int maxn = 1e5+100;
int flag[202][202][202];
int sign[202][202];
int mark[1000005];
int n, m;
int cnt , kind;
LL f[4];
int a[202], z;
int Next[202][202];
set<int> se;
void NextInit()
{
    for(int i = 0; i < z; i++){
        for(int j = i+1; j < z; j++){
            if(Next[i][a[j]]==-1){
                Next[i][a[j]] = j;
            }
        }
    }
}
void lisan()
{
    int cnt = 1;
    set<int>::iterator it;
    for(it = se.begin(); it!=se.end(); it++){
        mark[*it] = cnt;
        cnt++;
    }
    for(int i = 0; i < z; i++){
        a[i] = mark[a[i]];
    }
}
void init()
{
    memset(f, 0, sizeof f);
    memset(Next, -1, sizeof Next);
    memset(flag, 0, sizeof flag);
    memset(sign, 0, sizeof sign);
    se.clear();
}
int cal(int i,int j,int k)
{
    if(Next[i][a[j]]==j&&Next[j][a[k]]==k) return 3;
    if(Next[i][a[j]]==j) return 2;
    if(Next[j][a[k]]==k) return 2;
    if(Next[i][a[k]]==k) return 2;
    return 1;
}
void solve()
{
    kind = se.size();
    cnt = z;
    LL temp = m-kind;
    f[0] = 1LL*temp*temp*temp;
    ///枚举三层循环所有序列。
    for(int i = 0; i < z; i++){
        for(int j = 0; j < z; j++){
            for(int k = 0; k < z; k++){
                int len = cal(i,j,k);
                flag[a[i]][a[j]][a[k]] = max(flag[a[i]][a[j]][a[k]],len);
            }
        }
    }

    se.clear();///清空原先没有离散的数据。
    for(int i = 0; i < z; i++){
        se.insert(a[i]);
    }
    set<int>::iterator it, it1, it2;
    for(it = se.begin(); it!=se.end(); it++){
        for(it1 = se.begin(); it1!=se.end(); it1++){
            for(it2 = se.begin(); it2!=se.end(); it2++){
                f[flag[*it][*it1][*it2]]++;
            }
        }

    }

    ///枚举两层循环.
    int cnt2, cnt1;
    for(int i = 0; i < z; i++){
        for(int j = 0; j < z; j++){
            int len;
            if(Next[i][a[j]]==j) len = 2;
            else len = 1;
            sign[a[i]][a[j]]= max(sign[a[i]][a[j]],len);
        }
    }
    cnt1 = cnt2 = 0;
    for(it = se.begin(); it!=se.end(); it++){
        for(it1 = se.begin(); it1!=se.end(); it1++){
            if(sign[*it][*it1]==2){
                cnt2++;
            }else cnt1++;
        }
    }

    f[2] += 1LL*3*cnt2*(m-kind);
    f[1] += 1LL*3*cnt1*(m-kind);
    ///f(1)第三种来源;
    f[1] += 1LL*3*kind*(m-kind)*(m-kind);
}
int main()
{
    while(scanf("%d%d",&n,&m)==2)
    {
        z = 0;
        for(int i = 0; i < n; i++) {
            scanf("%d",&a[z]);
            if(a[z]<=m) z++;
        }
        init();
        for(int i = 0; i < z; i++){
            se.insert(a[i]);
        }
        lisan();
        NextInit();
        solve();
        printf("%I64d %I64d %I64d %I64d\n",f[0], f[1], f[2], f[3]);
    }
    return 0;
}
时间: 2024-08-09 00:28:14

2017-5-14 湘潭市赛 Longest Common Subsequence 想法题的相关文章

[HackerRank] The Longest Common Subsequence

This is the classic LCS problem. Since it requires you to print one longest common subsequence, just use the O(m*n)-space version here. My accepted code is as follows. 1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 5

uva 10405 Longest Common Subsequence (最长公共子序列)

uva 10405 Longest Common Subsequence Sequence 1: Sequence 2: Given two sequences of characters, print the length of the longest common subsequence of both sequences. For example, the longest common subsequence of the following two sequences: abcdgh a

Longest Common Subsequence (DP)

Given two strings, find the longest common subsequence (LCS). Your code should return the length of LCS. Example For "ABCD" and "EDCA", the LCS is "A" (or "D", "C"), return 1. For "ABCD" and &quo

Lintcode:Longest Common Subsequence 解题报告

Longest Common Subsequence Given two strings, find the longest comment subsequence (LCS). Your code should return the length of LCS. 样例For "ABCD" and "EDCA", the LCS is "A" (or D or C), return 1 For "ABCD" and "

Longest Common Subsequence &amp; Substring &amp; prefix

Given two strings, find the longest common subsequence (LCS). Your code should return the length of LCS. Example For "ABCD" and "EDCA", the LCS is "A" (or "D", "C"), return 1. For "ABCD" and &quo

LCS (Longest Common Subsequence)

LCS是两个序列相似性的一种度量方法: 若序列s1:2,5,7,9,3,1,2 s2:3,5,3,2,8 则LCS为:5,3,2 思路可参考:http://www.csie.ntnu.edu.tw/~u91029/LongestCommonSubsequence.html 具体代码实现为: 1 #include<iostream> 2 using namespace std; 3 4 int s1[7+1]={0,2,5,7,9,3,1,2}; 5 int s2[7+1]={0,3,5,3,2

UVA10405 Longest Common Subsequence【LCS+DP】

Given two sequences of characters, print the length of the longest common subsequence of both sequences. ????Sequence 1: ????Sequence 2: ????For example, the longest common subsequence of the following two sequences 'abcdgh' ans 'aedfhr' is 'adh' of

LeetCode 1143. Longest Common Subsequence

原题链接在这里:https://leetcode.com/problems/longest-common-subsequence/ 题目: Given two strings text1 and text2, return the length of their longest common subsequence. A subsequence of a string is a new string generated from the original string with some cha

1143. Longest Common Subsequence

link to problem Description: Given two strings text1 and text2, return the length of their longest common subsequence. A subsequence of a string is a new string generated from the original string with some characters(can be none) deleted without chan