题意:
N≤5×104的序列,0≤Ai≤109,求LIS的数量
分析:
f[i]:以第i个数结尾的LIS的长度,和该长度的LIS数量
转移的话,显然f[i].first=max{f[j].first}+1,j<i且a[j]<a[i]
f[i].second=∑jf[j].second,f[j].first=f[i].first−1
我们可以用BIT来优化这个转移,维护≤i的最大长度和对应数量
代码:
//
// Created by TaoSama on 2016-02-16
// Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
int n, a[N];
using P = pair<int, int>;
void getMax(P& x, P y) {
if(x.first < y.first) x = y;
else if(x.first == y.first) {
if((x.second += y.second) >= MOD)
x.second -= MOD;
}
}
struct BIT {
int n; P b[N];
void init(int _n) {
n = _n;
for(int i = 1; i <= n; ++i) b[i] = P(0, 0);
}
void add(int i, P v) {
for(; i <= n; i += i & -i) getMax(b[i], v);
}
P sum(int i) {
P ret(0, 1);
for(; i; i -= i & -i) getMax(ret, b[i]);
return ret;
}
} bit;
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
scanf("%d", &n);
vector<int> xs;
for(int i = 1; i <= n; ++i) {
scanf("%d", a + i);
xs.push_back(a[i]);
}
sort(xs.begin(), xs.end());
xs.resize(unique(xs.begin(), xs.end()) - xs.begin());
bit.init(xs.size());
P ans(0, 0);
for(int i = 1; i <= n; ++i) {
int x = lower_bound(xs.begin(), xs.end(), a[i]) - xs.begin() + 1;
P cur = bit.sum(x - 1);
++cur.first;
getMax(ans, cur);
bit.add(x, cur);
}
printf("%d\n", ans.second);
return 0;
}
当然其实这是个二维偏序问题,一维下标,二维值
直接cdq分治做就可以了,复杂度多一个log,是O(nlog2n)
为了避开相等有个小技巧,间隔排序很机智,把可能成为询问的排到了第一个,从知乎学到的@李贝瑀
代码:
//
// Created by TaoSama on 2016-02-16
// Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
int n, a[N];
using P = pair<int, int>;
P f[N]; //LIS length, count
void getMax(P& x, P y) {
if(x.first < y.first) x = y;
else if(x.first == y.first) {
if((x.second += y.second) >= MOD)
x.second -= MOD;
}
}
int id[N];
bool cmp(int x, int y) {
if(a[x] != a[y]) return a[x] < a[y];
return x > y;
}
void cdq(int l, int r) {
if(l == r) return;
int m = l + r >> 1;
cdq(l, m);
for(int i = l; i <= r; ++i) id[i] = i;
sort(id + l, id + r + 1, cmp);
P maxf(0, 0);
for(int i = l; i <= r; ++i) {
int idx = id[i];
if(idx <= m) getMax(maxf, f[idx]);
else {
P cur = maxf;
++cur.first;
getMax(f[idx], cur);
}
}
cdq(m + 1, r);
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%d", a + i);
for(int i = 1; i <= n; ++i) f[i] = P(1, 1);
cdq(1, n);
P ans(0, 0);
for(int i = 1; i <= n; ++i) getMax(ans, f[i]);
printf("%d\n", ans.second);
return 0;
}