首页 » 技术分享 » 凤凰院凶真 解题报告

凤凰院凶真 解题报告

 

凤凰院凶真

Description

\(α\) 世界线.

凤凰院凶真创立了反抗 \(SERN\) 统治的组织 “瓦尔基里”. 为了脱离 \(α\) 线, 他需要制作一个世界线
变动率测量仪.

测量一个世界线相对于另一个世界线的变动率, 实质上就是要求出这两个世界线的最长公共合
法事件序列.

一个世界线的事件逻辑序列是一个正整数序列, 第 \(k\) 个数表示第 \(k\) 个事件发生的时间.

对于一个世界线, 一个合法的事件序列是事件逻辑序列的一个子序列, 满足时间严格递增.

现在, 对于两个不同的世间线 \(α\) ,\(β\), 求出最长的一个事件序列, 满足这个序列在 \(α,β\) 世界线中
均是合法的.

这个序列也就是之前提到过的最长公共合法事件序列

Input Format

第一行一个整数 \(n\), 表示 \(α\) 世界线的事件个数.
第二行 \(n\) 个整数 \(a_1,a2,\dots,a_n\), 表示 \(α\) 世界线的事件逻辑序列.
第三行一个整数 \(m\), 表示 \(β\) 世界线的事件个数.
第四行 \(m\) 个整数 \(b_1,b_2,\dots,b_m\), 表示 \(β\) 世界线的事件逻辑序列.

Output Format

第一行一个整数 \(k\), 表示最长公共合法事件序列的长度.
第二行 \(k\) 个整数, 表示最长公共合法事件序列. 如果有多解, 输出任意一个.

Constraints

无论执迷过去
还是叹息未来
皆是不准有丝毫误算的必然

子任务编号 分数 \(n,m\) \(a_i,b_i\)
1 10 \(\le 10\) \(\le 2^{30}\)
2 10 \(\le 20\) \(\le 2^{30}\)
3 10 \(\le 100\) \(\le 2^{30}\)
4 15 \(\le 400\) \(\le 2^{30}\)
5 15 \(\le 1000\) \(\le 200\)
6 15 \(\le 1000\) \(\le 2^{30}\)
7 25 \(\le 5000\) \(\le 2^{30}\)

对于\(100\%\)的数据,\(1 \le n,m \le 5000,1 \le a_i,b_i \le 2^{30}\)

Solution

就是\(LCIS\)问题啦,其实还是比较巧妙的感觉

\(dp_{i,j}\)代表\(a\)串前\(i\)个位置与\(b\)串前\(j\)个位置匹配并且\(j\)为匹配的末尾的最长长度。

朴素的,有

\(a_i=b_j\),则\(dp_{i,j}=\max\limits_{b_k<a_i} dp_{i-1,k}+1\)

否则,\(dp_{i,j}=dp_{i-1,j}\)

发现\(k\)那一维是不需要枚举的,直接用前缀最大值优化一下就可以了,因为在\(i\)一定时,决策集合是递增的。


Code:

#include <cstdio>
const int N=510;
int dp[N][N],pre[N][N],ans[N],tot,n,m,a[N],b[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    scanf("%d",&m);
    for(int i=1;i<=m;i++) scanf("%d",b+i);
    for(int i=1;i<=n;i++)
    {
        int mx=0,id=0;
        for(int j=1;j<=m;j++)
        {
            if(a[i]==b[j])
                dp[i][j]=mx+1,pre[i][j]=id;
            else
                dp[i][j]=dp[i-1][j];
            if(dp[i-1][j]>mx&&a[i]>b[j]) mx=dp[i-1][j],id=j;
        }
    }
    int mx=0,r1=n,r2;
    for(int i=1;i<=m;i++)
        if(mx<dp[n][i])
            mx=dp[n][i],r2=i;
    ans[++tot]=r2;
    printf("%d\n",mx);
    if(mx==0) return 0;
    while(r1&&r2)
    {
        if(pre[r1][r2])
        {
            r2=pre[r1][r2];
            ans[++tot]=r2;
        }
        else
            --r1;
    }
    for(int i=tot;i;i--)
        printf("%d ",b[ans[i]]);
    return 0;
}

2018.10.19

转载自原文链接, 如需删除请联系管理员。

原文链接:凤凰院凶真 解题报告,转载请注明来源!

0