凤凰院凶真
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}=maxlimits_{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
",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