您的位置:首页 > 产品设计 > UI/UE

2016 UESTC Training for Dynamic Programming N - 柱爷与子序列 这题和N题有些相似之处、用了树状数组

2016-05-17 12:21 447 查看


N - 柱爷与子序列


Time Limit: 1000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)


Submit
Status

柱爷是个爱思考的人。这天,柱爷在思考子序列的问题。
所谓数列A1,A2,…,An的子序列,是指Ab1,Ab2,…,Abm,
满足1≤b1<b2<...<bm≤n

当然,这样的子序列有很多。但柱爷要找的是完美子序列!


所谓完美子序列,还需满足以下条件:


m≥2


|Abi−Abi+1|≤k,1≤i<m

现在问你,数列中一共有多少完美子序列。
答案可能很大,输出对1000000009取模。


Input

第一行输入两个数n,k 。
第二行输入n个数,表示Ai的值。
数据保证:

2≤n≤100000,1≤k≤100000000

1≤Ai≤100000000


Output

输出仅一个数,完美子序列的数量。答案可能很大,输出对1000000009取模。


Sample input and output

Sample InputSample Output
4 2
1 3 7 5

4


Hint

对于样例,存在以下4个完美子序列:

1,3

1,3,5

3,5
7,5


Source

2016 UESTC Training for Dynamic Programming


My Solution

这题和N题有些相似之处^_^

题意:求所有相邻元素之差<=k的子序列数量

dp[i]表示以a[i]结尾的子序列数量

dp[i] = sum(dp[j])

0<j<i, a[i]-k<=a[j]<=a[i]+k

数值很大,先离散化

用线段树或树状数组记录dp[j]的区间和, 这里选了树状数组

单点更新,区间查询

dp=get(r) - get(l-1);

Update(x ,dp + 1);

要有+1 然后最后输出的时候 - n, 把多加了的1减掉

然后ans就是所以的dp值的和

注意点, 在树状数组里面也要进行取模,不然会溢出

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 100000 + 8, HASH = 1000000009;
int a[maxn], b[maxn], nn;
//LL dp[maxn];

LL Tree[maxn];

inline int lowbit(int x)
{
return (x&-x);
}

void add(int x, LL value)
{
for(int i = x; i <= nn; i += lowbit(i))
Tree[i] = (Tree[i] + value) % HASH;
}

LL get(int x)
{
LL sum = 0;
for(int i = x; i; i -= lowbit(i))
sum =(sum + Tree[i]) % HASH;
return sum;
}
//!WA7 然后直接给中间过程已经树状数组里面也直接全部取模了☺☺
int main()
{
#ifdef LOCAL
freopen("a.txt", "r", stdin);
#endif // LOCAL
int n, k, x, l, r;
long long dp;  //dp[maxn] ==>> dp
scanf("%d%d", &n, &k);
for(int i = 0; i < n; i++)
scanf("%d", &a[i]);
memcpy(b, a, sizeof a);
sort(a, a + n);
nn = unique(a, a + n) - a;

memset(Tree, 0, sizeof Tree);
for(int i = 0; i < n; i++){                            //!这里坐标统一为 1 ~ nn 了
x = lower_bound(a, a + nn, b[i]) - a + 1;
l = lower_bound(a, a + nn, b[i] - k) - a + 1;
r = upper_bound(a, a + nn, b[i] + k) - a;          //返回最后一个b[i]的后面一个位置。
//cout<<"x = "<<x<<" l = "<<l<<" r = "<<r<<endl;
dp = (get(r) - get(l-1))%HASH;                            //有一个 l - 1的所以还是 1 ~ nn 好
add(x, dp+1);                                      //修改的时候不能是0的不然 0&-0一直这样会死循环,当然,这里x 不会是0
}
printf("%lld", (get(nn) - n +HASH)%HASH); //ans 不是 dp[n-1] ☺☺
return 0;
}


Thank you!

------from ProLights
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: