凤凰院凶真 解题报告
凤凰院凶真
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