[codevs2245] 股票趋势 二维线段树

本文探讨了一个特定的计算机科学问题——有间距限制的最长公共子序列(GLCS)。介绍了如何通过分析两串字母序列来寻找它们之间的相似度,尤其是在考虑了间距限制的情况下。文中提供了一种使用二维线段树的方法来解决这个问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述 Description

彭先生任职于证券公司,是一位股票分析师。公司经理认为目前的股票分析软件仍可再改进,希望彭先生再设计一套更准确的软件。近日來,彭先生埋头钻研,他发现过去的研究结果,有人提到,如果能在历史资料中,找到与近期股票走势相近的样型,即可使用此历史样型的交易策略,做为近期的买卖策略。为了验证这样的讲法是否正确,彭先生从股票历史资料抽出一些特征资料,并以大写英文字母A~Z 代表特征资料,因此股票资料变成一串的英文字母序列。判断近期股票资料与某一段历史资料是否相近,就变成判断二串字母序列( 长度不一定相等) 的相似度,亦即找出兩者的最长共同子序列(LCS,longest common subsequence) 。

在计算二串股票资料序列的相似度时,还有一个限制,兩个相似点( 相同字母) 的前后间距不能太远,否则相似度会被扭曲。发现了这个特性后,彭先生将此问题正式定义为「有间距限制的最长共同子序列」(GLCS, gapped longest common subsequence)问题。

假设第一个序列称为α,第二个序列称为β。例如,α =“ACBDCAA”,β=“ADDBCDBAC” 。兩者在无间距限制的情形下,其 LCS 可为“ADCA” , “ABCA” ,或“ACBC” ,长度为4。假设间距限制如下: 

A 2, B 0, C 3, D 0

 上述间距之意义为,如果字母A 被选入LCS 中,则与其前一个被选入的字母之间,在α序列最多只能有2 个未被选入的字母,在β序列亦同。α与β在上述间距限制的情形,GLCS 可为“ACA” 或“ACC” ,长度为3。

对于无间距限制的情形,可将每个字母的间距视为无限大。本题的答案只要输出GLCS 的长度即可。

输入描述 Input Description

共分成二部分。第一部分,第一行为α序列,第二行为β序列,兩者都是大写英文字母A~Z 的序列,每个序列长度至少为 1,最长为 800。第二部分自第三行起,第三行有一个数值 k,代表以下有 k 组测试资料(1 ≤ k≤ 5) ,每一组测试资料为一行,每一行有多个( 可能零个) 字母间距限制,每个限制的第一个为英文字母,第二个为间距数值( 数值介于0 与400 之间);英文字母不一定按照顺序,也不一定每个字母都会出现,未出现的字母间距可视为无限大。每一行字母间距限制的最后一个符号为$ ,代表该行( 该组) 的资料结束。每一行的字母间距限制情形,相邻兩项资料之间均有一个空白隔开。

输出描述 Output Description

对于每一组测试资料,输出它的 GLCS 长度。输出这 k 个值于一行,且相邻兩个整数之间以一个空白隔开。

dp[i][j]A串到i,B串到j的最大值(i,j必须选)

转移的时候dp[i][j] = max( dp[k][l] )( i-len[A[i]]-1 <= k < i, j-len[B[j]]-1 <= l < j ) + 1

反正我不知道怎么用单调队列优化

直接YY了个二维线段树

可惜考试的时候query忘了返回值qwq

floj卡常差评!

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <bitset>
#include <queue>
#include <map>
#include <set>
typedef long long ll;
using namespace std;
const int N = 800 + 5;
char s1[N], s2[N], s[5];
int l1, l2, len[31], T, dp[N][N], ans;
void init(){
	ans = 0;
	memset( dp, 0, sizeof(dp) );
	memset( len, -1, sizeof(len) );
}
int ls[N*4000], rs[N*4000], sz, root, flag[N*4000], mx[N*4000], rt[N*4000];
void buiId( int &k, int l, int r ){
	if( !k ) k = ++sz;
	if( l == r ) return ;
	int mid = l + r >> 1;
	buiId( ls[k], l, mid );
	buiId( rs[k], mid + 1, r );
}
void build( int &k, int l, int r ){
	if( !k ) k = ++sz;
	buiId( rt[k], 0, l2 );
	if( l == r ) return ;
	int mid = l + r >> 1;
	build( ls[k], l, mid );
	build( rs[k], mid + 1, r );
}
void pushdown( int k ){
	if( flag[k] ){
		mx[ls[k]] = max( mx[ls[k]], flag[k] );
		mx[rs[k]] = max( mx[rs[k]], flag[k] );
		flag[ls[k]] = max( flag[ls[k]], flag[k] );
		flag[rs[k]] = max( flag[rs[k]], flag[k] );
		flag[k] = 0;
	}
}
void update( int k ){
	mx[k] = max( mx[ls[k]], mx[rs[k]] );
}
void changc( int k, int l, int r, int L, int R, int val ){
	if( L <= l && R >= r ){
		flag[k] = max( flag[k], val );
		mx[k] = max( mx[k], val );
		return ;
	}
	int mid = l + r >> 1;
	pushdown( k );
	if( L <= mid ) changc( ls[k], l, mid, L, R, val );
	if( R >  mid ) changc( rs[k], mid + 1, r, L, R, val );
	update( k );
}
void change( int k, int l, int r, int L, int R, int lf, int rg, int val ){
	changc( rt[k], 0, l2, lf, rg, val );
	if( L <= l && R >= r ) return ;
	int mid = l + r >> 1;
	if( L <= mid ) change( ls[k], l, mid, L, R, lf, rg, val );
	if( R >  mid ) change( rs[k], mid + 1, r, L, R, lf, rg, val );
}
int qucry( int k, int l, int r, int L, int R ){
	if( L <= l && R >= r ) return mx[k];
	int mid = l + r >> 1, res = 0;
	pushdown( k );
	if( L <= mid ) res = max( res, qucry( ls[k], l, mid, L, R ) );
	if( R >  mid ) res = max( res, qucry( rs[k], mid + 1, r, L, R ) );
	update( k );
	return res;
}
int query( int k, int l, int r, int L, int R, int lf, int rg ){
	if( L <= l && R >= r )
		return qucry( rt[k], 0, l2, lf, rg );
	int mid = l + r >> 1, res = 0;
	if( L <= mid ) res = max( res, query( ls[k], l, mid, L, R, lf, rg ) );
	if( R >  mid ) res = max( res, query( rs[k], mid + 1, r, L, R, lf, rg ) );
	return res;
}
int main(){
//	freopen("glcs.in","r",stdin);
//	freopen("glcs.out","w",stdout);
	scanf( "%s", s1 + 1 ); scanf( "%s", s2 + 1 );
	l1 = strlen(s1 + 1); l2 = strlen(s2 + 1);
	scanf( "%d", &T );
	build( root, 0, l1 );
	while( T-- ){
		init();
		memset( flag, 0, sizeof(flag) );
		memset( mx, 0, sizeof(mx) );
		while( scanf( "%s", s ) && s[0] != '$' ){
			int x, y; x = s[0] - 'A';
			scanf( "%d", &y ); len[x] = y;
		}
		for( int i = 1; i <= l1; i++ )
			for( int j = 1; j <= l2; j++ )
				if( s1[i] == s2[j] ){
					int fa = ( len[s1[i] - 'A'] == -1 ) ? 0 : max( 0, i - len[s1[i] - 'A'] - 1 );
					int fb = ( len[s2[j] - 'A'] == -1 ) ? 0 : max( 0, j - len[s2[j] - 'A'] - 1 );/*
					for( int k = fa; k < i; k++ )
						for( int l = fb; l < j; l++ )
							dp[i][j] = max( dp[i][j], dp[k][l] + 1 );*/
					dp[i][j] = query( root, 0, l1, fa, i - 1, fb, j - 1 ) + 1;
					change( root, 0, l1, i, i, j, j, dp[i][j] );
					ans = max( ans, dp[i][j] );
//					printf( "f[%d][%d] = %d\n", i, j, dp[i][j] );
				}
		printf( "%d ", ans );
	}
	return 0;
}
/*
ACBDCAA
ADDBCDBAC
2
$
A 2 B 0 C 3 D 0 $
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值