嘘~ 正在从服务器偷取页面 . . .

模拟赛题讲解[31]


模拟赛题讲解[31]

来自 yukuai26 2023-08-05 noi.ac #3275

题目描述

给定 \(N\)个单调递增的数 \(A_i\)\(M\)个单调递增的数 \(B_i\),从 \(A\)\(B\)中分别找到一个子序列 \(a,b\),使得这两个子序列长度一样并且 \(a_i-a_{i+1}=b_i-b_{i+1}\)。求这两个子序列的最长长度。

输入格式

第一行两个整数 \(N,M\)

接下来一行 \(N\)个整数代表 \(A\)

接下来一行 \(M\)个整数代表 \(B\)

输出格式

输出一行一个整数代表答案。

输入样例

5 5
1 2 3 4 5
4 6 7 8 10

输出样例

4

数据范围

对于 \(100\%\)的数据,\(1\leq N,M\leq 1000,1\leq A_i,B_j\leq 10000\)

题解

居然没想到正解,我真是 stupid 啊。

先讲讲暴力dp解法。设 \(f_{i,j}\) 表示考虑到 \(a\) 的前 \(i\) 个数和 \(b\) 的前 \(j\) 个数,强制选了 \(a_i,b_j\) ,直接看代码:

for(int i = 1; i <= n; i++)
    for(int j = 1; j <= n; j++) f[i][j] = 1;
for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++)
        for(int k = 1; k < i; k++)
            for(int l = 1; l < j; l++)
                if(a[i] - a[k] == b[j] - b[l]) up(f[i][j], f[k][l] + 1), up(res, f[i][j]);
cout << res << '\n';

开始讲正解。考虑移项,则 \(a_i - b_i = a_{i+1}-b_{i+1}\)

因此我们只要去出现次数最大 \(a_i-b_i\) 的那些 \(i\) 就好了

这样为啥对呢,因为都是单调递增的,所以不会有重复的数,就这么水。

时间复杂度 \(\mathcal{O}(n + M)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e3 + 15))
#define M ((int)(2e4 + 55))

int n,m,a[N],b[N],cnt[M];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    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 = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) ++cnt[a[i] - b[j] + 10000ll];
    cout << *max_element(cnt, cnt + 20000 + 30) << '\n';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录