题目链接: http://codeforces.com/problemset/problem/474/E
题解: 设f[i]为以位置i为结束的字串,那么方程为f[i] = max{ f[j] } + 1 (abs(a[j] - a[i]) >= k) 复杂度O(n * n),超时。
所有出现过的数字排序去重离散化,建线段树维护区间最大值,对于每个a[i] 查询[0, a[i] - k] ∪ [a[i] + k, INF]的最大值,然后向线段树插入f[i],总复杂度O(n * log(n))
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL long long
#define N 400000
using namespace std;
struct node
{
LL a, b;
node *l, *r;
LL s;
LL pos;
}f[N], *top;
LL cnt;
LL num[N], a[N];
LL dp[N];
LL pre[N];
LL n, d;
LL q[N];
node* build(LL a, LL b)
{
cnt++;
LL tmp = cnt;
f[cnt].a = a; f[cnt].b = b;
f[cnt].s = 0;
f[cnt].l = f[cnt].r = NULL;
if(a < b)
{
LL mid = (a + b) / 2;
f[tmp].l = build(a, mid);
f[tmp].r = build(mid + 1, b);
}
return f + tmp;
}
void insert(node *t, LL a, LL c, LL p)
{
if(a <= t->a && t->a == t->b) { if(c >= t->s) { t->s = c; t->pos = p; } }
else
{
LL mid = (t->a + t->b) / 2;
if(a <= mid) insert(t->l, a, c, p);
else insert(t->r, a, c, p);
if(t->l->s > t->r->s) t->pos = t->l->pos;
else t->pos = t->r->pos;
t->s = max(t->l->s, t->r->s);
}
}
LL findMax(node *t, LL a, LL b, LL &pos)
{
if(a <= t->a && t->b <= b) { pos = t->pos; return t->s; }
LL s = 0;
LL mid = (t->a + t->b) / 2;
LL p1;
if(a <= mid)
{
LL p = findMax(t->l, a, b, p1);
if(p > s)
{
s = p;
pos = p1;
}
}
if(b > mid)
{
LL p = findMax(t->r, a, b, p1);
if(p > s)
{
s = p;
pos = p1;
}
}
return s;
}
LL shuffle(LL f[], LL n)
{
LL cnt = 0;
for(LL i = 0; i < n; i++)
{
if(i == 0 || f[i] != f[i - 1]) f[cnt++] = f[i];
}
return cnt;
}
LL find1(LL x, LL f[], LL n)
{
LL l = 0, r = n - 1;
while(l < r - 1)
{
LL mid = (l + r) / 2;
if(x <= f[mid]) r = mid;
else l = mid;
}
if(x == f[r]) return r;
return l;
}
LL find(LL x, LL f[], LL n)
{
LL l = 0, r = n - 1;
while(l < r - 1)
{
LL mid = (l + r) / 2;
if(x <= f[mid]) r = mid;
else l = mid;
}
if(x == f[l]) return l;
return r;
}
int main()
{
//freopen("test.in", "r", stdin);
scanf("%I64d%I64d", &n, &d);
for(LL i = 0; i < n; i++) scanf("%I64d", &a[i]);
for(LL i = 0; i < n; i++) num[i] = a[i];
LL l = n;
num[n] = -1e15 - 7;
n++;
num[n] = 1e15 + 7;
n++;
num[n + 2] = 0;
n++;
sort(num, num + n);
LL nn = shuffle(num, n);
//for(LL i = 0; i < nn; i++) cout <<num[i] <<" ";
//cout << endl;
memset(dp, 0, sizeof dp);
LL ans = 0;
LL kk;
top = build(0, nn + 1);
for(LL i = 0; i < l; i++)
{
LL pos1, pos2;
//cout << a[i] - d << " " << a[i] <<" "<< a[i] + d << endl;
//cout << num[find1(a[i] - d, num, nn)] << " " << num[find(a[i] + d, num, nn)] <<endl <<endl;
LL a1 = findMax(top, 0, find1(a[i] - d, num, nn), pos1);
LL a2 = findMax(top, find(a[i] + d, num, nn), nn, pos2);
dp[i] = 1;
pre[i] = -1;
if(a1 > a2) { dp[i] += a1; pre[i] = pos1; }
else { dp[i] += a2; pre[i] = pos2; }
//cout << i << " "<< a[i] <<" "<< pre[i] << " " <<dp[i] << endl;
if(dp[i] > ans) { kk = i; ans = max(ans, dp[i]); }
insert(top, find(a[i], num, nn), dp[i], i);
}
l = ans;
while(l)
{
q[l + 1] = kk;
kk = pre[kk];
l--;
}
printf("%I64d\n", ans);
for(LL i = 2; i <= ans + 1; i++) printf("%I64d ", q[i] + 1);
return 0;
}