[思维]Longest Common Subsequence 2022牛客多校第8场 F

59 篇文章 0 订阅

题目描述

Given sequence ss of length nn and sequence tt of length mm, find the length of the longest common subsequence of ssand tt.

输入描述:

There are multiple test cases. The first line of input contains an integer TT(1≤T≤1031≤T≤103), the number of test cases.

For each test case:

The only line contains 77 integers, nn, mm, pp, xx, aa, bb, cc (1≤n1≤n, m≤106m≤106, 0≤x0≤x, aa, bb, c<p≤109c<p≤109). nn is the length of ss, mm is the length of tt.

To avoid large input, you should generate the sequences as follows:

For each i=1i=1, 22, ⋯⋯, nn in order, update xx to (ax2+bx+c) mod p(ax2+bx+c)modp, and then set sisi​ to xx. And then, for each i=1i=1, 22, ⋯⋯, mm in order, update xx to (ax2+bx+c) mod p(ax2+bx+c)modp, and then set titi​ to xx.

It is guaranteed that the sum of nn and the sum of mm over all test cases does not exceed 106106.

输出描述:

For each test case:

Output an integer -- the length of the longest common subsequence of ss and tt, in one line.

示例1

输入

2
4 3 1024 1 1 1 1
3 4 1024 0 0 0 0

输出

0
3

说明

In the first sample, s=[3,13,183,905]s=[3,13,183,905] and t=[731,565,303]t=[731,565,303].

In the second sample, s=[0,0,0]s=[0,0,0] and t=[0,0,0,0]t=[0,0,0,0].

题意: 给出一个长度为n的数组以及一个长度为m的数组,求它们的最长公共子序列,数组中的值按照一定规则生成,给出x、a、b和c,令x = a*x^2 + b*x + c,然后把x填入数组中第i个位置,如此往复直至遍历完数组。

分析: 由于n和m都是1e6级别的,所以没法直接跑n^2的lcs算法,可以注意到两个数组中数据生成都是有规律的,第i+1个位置的值是通过第i个位置的值得到的,如果一旦出现a[i]等于b[j],那么a数组第i个位置和b数组第j个位置后面的值一定是相同的,所以问题就很好解决了,只需要记录下a数组中a[i]首次出现的位置,然后遍历b数组,当b[i]在a数组中出现过时,就可以更新一次答案,最终结果取最大值。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <unordered_map>
using namespace std;

unordered_map<int, int> mp;

signed main()
{
	int T;
	cin >> T;
	while(T--){
		mp.clear();
		int n, m, p, x, a, b, c;
		scanf("%d%d%d%d%d%d%d", &n, &m, &p, &x, &a, &b, &c);
		for(int i = 1; i <= n; i++){
			x = ((1ll*a*x%p*x%p+1ll*b*x%p)%p+c)%p;
			if(!mp.count(x))
				mp[x] = i;
		}
		int ans = 0;
		for(int i = 1; i <= m; i++){
			x = ((1ll*a*x%p*x%p+1ll*b*x%p)%p+c)%p;
			if(mp[x]) ans = max(ans, min(n-mp[x]+1, m-i+1));
		}
		printf("%d\n", ans);
	} 
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值