【题目】
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
1≤i1<i2<…<iK≤N
. 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 ).
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]
1≤n≤100000
0≤ai≤1000000000
Process to the end of file.
[Technical Specification]
1≤n≤100000
0≤ai≤1000000000
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;
}