题解
题目大意 给一个长度为n的序列 问他的子序列(不连续)中有多少个完美子序列 完美子序列要求相邻两个元素的差不大于d
按照值建立线段树 每个数字a[i]的贡献就是他前面出现过的a[i] - d到a[i] + d范围内数字的贡献和 使用线段树维护
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5 + 10;
const int MOD = 9901;
int a[MAXN];
vector<int> dz;
struct node
{
int l, r;
ll v;
}tre[MAXN * 4];
inline void PushUp(int x)
{
tre[x].v = (tre[x << 1].v + tre[x << 1 | 1].v) % MOD;
}
void Build(int x, int l, int r)
{
tre[x].l = l, tre[x].r = r, tre[x].v = 0;
if (l == r)
return;
else
{
int m = l + r >> 1;
Build(x << 1, l, m);
Build(x << 1 | 1, m + 1, r);
}
}
void Update(int x, int p, ll v)
{
int l = tre[x].l , r = tre[x].r;
if (l == r)
tre[x].v = (tre[x].v + v) % MOD;
else
{
int m = l + r >> 1;
if (m >= p)
Update(x << 1, p, v);
else
Update(x << 1 | 1, p, v);
PushUp(x);
}
}
ll Query(int x, int pl, int pr)
{
int l = tre[x].l, r = tre[x].r;
if (pl <= l && r <= pr)
return tre[x].v;
else
{
int m = l + r >> 1;
ll v = 0;
if (m >= pl)
v = (v + Query(x << 1, pl, pr)) % MOD;
if (m < pr)
v = (v + Query(x << 1 | 1, pl, pr)) % MOD;
return v;
}
}
int Dis(int v)
{
return lower_bound(dz.begin(), dz.end(), v) - dz.begin();
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int N, D;
while (cin >> N >> D)
{
dz.clear();
dz.push_back(-INF);
for (int i = 1; i <= N; i++)
scanf("%d", &a[i]), dz.push_back(a[i]);
sort(dz.begin(), dz.end());
dz.erase(unique(dz.begin(), dz.end()), dz.end());
ll ans = 0;
Build(1, 1, N);
for (int i = 1; i <= N; i++)
{
int m = Dis(a[i]); //当前位置
int l = Dis(a[i] - D); //大于等于a[i] - d位置
int r = Dis(a[i] + D + 1) - 1; //小于等于a[i] + d位置
ll res = Query(1, l, r);
ans = (ans + res) % MOD;
Update(1, m, res + 1);
}
cout << ans << endl;
}
return 0;
}