HDU5141 - LIS again(LIS的变形)

【题目】

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 numbers a1,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、付费专栏及课程。

余额充值