HDU5141 - LIS again(LIS的变形)

本文讨论了如何在给定的数列中找出等长于最长上升子序列的所有子序列数量。通过实例和代码解析,展示了具体的实现步骤。

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

【题目】

LIS again

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 232    Accepted Submission(s): 74


Problem Description
A numeric sequence of ai is ordered if a1<a2<<aN. Let the subsequence of the given numeric sequence (a1,a2,,aN) be any sequence (ai1,ai2,,aiK), where 1i1<i2<<iKN. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, eg. (1, 7), (3, 4, 8) and many others.
S[ i , j ] indicates ( ai,ai+1,ai+2,,aj) .
Your program, when given the numeric sequence (a1,a2,,aN), must find the number of pair ( i, j)  which makes the length of the longest ordered subsequence of S[ i , j ] equals to the length of the longest ordered subsequence of (a1,a2,,aN).
 


 

Input
Multi test cases (about 100), every case occupies two lines, the first line contain n, then second line contain n numbersa1,a2,,aN separated by exact one space.
Process to the end of file.

[Technical Specification]
1n100000
0ai1000000000
 


 

Output
For each case,.output the answer in a single line.
 


 

Sample Input
3 1 2 3 2 2 1
 


 

Sample Output
1 3

 

 

【分析】

题目要求的是等于最长上升序列的子串数量,只要求出以i结尾长度等于最长上升子序列的长度的最靠右的左下标,累加起来就是答案,不需要用线段树。具体看代码注释。

【AC CODE】 246ms

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <map>
//#include <unordered_map>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 100000+10;
int d[MAXN], p[MAXN];//p[i]表示以i结尾时最k靠右的左下标(下面简称左下标),也就是数量

int main()
{
#ifdef SHY
	freopen("e:\\1.txt", "r", stdin);
#endif
	int n;
	while(~scanf("%d%*c", &n))
	{
		int a, len = 0;
		LL ans = 0;
		d[0] = -1;
		repe(i,1,n)
		{
			scanf("%d%*c", &a);
			int k = lower_bound(d,d+len,a)-d;
			d[k++] = a;//k++变成1开始的下标
			if(1 == k) p[k] = i;//k==1时长度为1,左下标则为i(新起点)
			else p[k] = p[k-1];//否则p[k] = p[k-1]的值,因为是连续的,所以修改和增加长度都不会改变左下标
			if(k > len)//长度增加时ans要重置为新长度的数量
				ans = p[++len];
			else ans += p[len];//长度不变时说明有新方案长度也能等于len,累加
		}
		printf("%I64d\n", ans);
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值