1 条题解

  • 0
    @ 2026-9-24 10:20:03

    首先考虑一个时空复杂度都是 O(n2)O(n^2) 的做法:

    首先求出 ai,bia_i,b_i 中的每一个数下一次的出现位置 nxtai,nxtbinxta_i,nxtb_i。类似于正常的 LCS,设 dpi,jdp_{i,j} 为考虑 aa 的前 ii 项,bb 的前 jj 项的最长公共口吃序列长度,考虑向后转移,显然有以下转移:

    • dpi+1,j←dpi,jdp_{i+1,j}\leftarrow dp_{i,j},dpi,j+1←dpi,jdp_{i,j+1}\leftarrow dp_{i,j};
    • 特别地,若 ai+1=bj+1a_{i+1}=b_{j+1},则 dpnxtai+1,nxtbj+1←dpi,j+2dp_{nxta_{i+1},nxtb_{j+1}}\leftarrow dp_{i,j}+2。

    由于空间限制只有 32MB,而当前的状态转移又无法进行滚动数组优化,考虑重新设计状态。

    仔细分析转移过程,考虑如何将第二步写成能够滚动数组优化的形式。现在的转移过程是 i→nxtai+1i\to nxta_{i+1},j→nxtbj+1j\to nxtb_{j+1},不如我们先将 jj 一步移动到 nxtbj+1nxtb_{j+1},并对当前状态进行标记,代表 ii 目前只匹配了一次,在转移的过程中,不断将 ii 往右移,不改变 jj 的值,直到发现 ai=bja_i=b_j(此时的 jj 就相当于原来的 nxtbj+1nxtb_{j+1}),完成一次匹配。

    这样我们只会从 dpidp_i 转移到 dpi+1dp_{i+1},可以使用滚动数组优化。具体的转移可以参考代码。其中的一个细节是,若发现 ai+1=bj+1a_{i+1}=b_{j+1},我们只能将 dpi+1,nxtbj+1,1dp_{i+1,nxtb_{j+1},1} 更新,但是此时 ai+1=bnxtbj+1a_{i+1}=b_{nxtb_{j+1}},因此我们完成匹配时判断的是 ai+1a_{i+1} 和 bjb_j 是否相等。

    ::::info[AC 代码] Submission

    #include <bits/stdc++.h>
    using namespace std;
    int n, m, a[16000], b[16000], nxta[16000], nxtb[16000], pre[16000][2], dp[16000][2], nxt[16000][2];
    map<int, int> mp;
    int main() {
    	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    	cin >> n >> m;
    	for (int i = 1; i <= n; i++)
    		cin >> a[i];
    	for (int i = 1; i <= m; i++)
    		cin >> b[i];
    	for (int i = m; i >= 1; i--) {
    		if (mp[b[i]]) nxtb[i] = mp[b[i]];
    		mp[b[i]] = i;
    	}
    	for (int i = 0; i <= m; i++)
    		pre[i][1] = -0x3f3f3f3f;
    	for (int i = 0; i <= n; i++) {
    		for (int j = 0; j <= m; j++)
    			dp[j][0] = dp[j][1] = -0x3f3f3f3f;
    		for (int j = 0; j <= m; j++) {
    			pre[j + 1][0] = max(pre[j + 1][0], pre[j][0]);
    			dp[j][0] = max(dp[j][0], pre[j][0]);
    			if (a[i + 1] == b[j + 1] && nxtb[j + 1]) dp[nxtb[j + 1]][1] = max(dp[nxtb[j + 1]][1], pre[j][0]);
    			if (a[i + 1] == b[j]) dp[j][0] = max(dp[j][0], pre[j][1] + 2);
    			else dp[j][1] = max(dp[j][1], pre[j][1]);
    		}
    		for (int j = 0; j <= m; j++)
    			pre[j][0] = dp[j][0], pre[j][1] = dp[j][1];
    	}
    	cout << max(pre[m][0], pre[m][1]);
    	return 0;
    }
    

    ::::

    • 1

    信息

    ID
    5761
    时间
    3000ms
    内存
    132MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者