题目
题目描述
Marton的朋友Cero有一个包含N个正整数的数组。开始时,Cero在黑板上写上第一个数字,然后,他将第二个数字写在第一个数字的左边或右边,之后,他将第三个数字写在目前为止写下的所有数字的左边或右边,以此类推。当他写下全部N个数字后,会形成一个新的数组。
●Marton想知道新数组的最长严格递增子序列的长度。
●Marton还想知道这种最长严格递增子序列的数量。
更确切的说,如果所有能构建出的新数组中最长严格递增子序列的最长长度为M,则想Marton知道所有可以构建的每个新数组中长度为M的最长严格递增子序列的数目的总和。如果新数组使用不同的顺序构建,则称为不同的新数组。对于同一个新数组,如果两个最长严格递增子序列在至少一个位置上不同,则称为两个不同的最长严格递增子序列。 考虑到这样的子序列的数目非常大,只需求出答案对109+7取模的结果。 Cero要求你来回答Marton的两个问题。
输入格式
第一行输入包含整数N(1≤N≤2*1e5)。表示数组中有多少个数。 第二行输入包含N个正整数Ai(1≤Ai≤1e9)。表示Cero原本的数组。
输出格式
输出两个整数,中间用空格分隔。分别表示最长严格递增子序列的长度和这种长度的最长严格递增子序列的的数目。
样例
样例输入1
2
1 1
样例输出1
1 4
样例输入2
4
2 1 3 4
样例输出2
4 1
分析&题解
首先看到这道题是可以想到dp
其实题目就是说有一些数字跑到了第1个数的左边,求现在新数组的最长严格上升子序列并求其个数
想一想,如果把在其左边的数翻转过来是什么?就是最长严格下降子序列吧?那么就可以直接在原数组上完成就行了,考虑到n较大,只能选用O(nlog(n))的算法了
定义dp[i]表示以i为起点的最长严格上升(下降)子序列 , cnt[i]表示以i为起点的最长严格上升(下降)子序列的个数
这时我们就需要用到树状数组了,要记录一下前面的dp值
那么怎么统计个数呢?也很简单,如果我们发现两个点的dp值是一样的就把他们的个数(cnt)相加,在树状数组上是可以完成的。待会代码再说…
错误的方法
(留给自己看的,可以跳过)
这道题有点坑呀,也可能是第一次写树状数组优化,被坑了很多次
首先是
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
const int MAX