hdu 3450 Counting Sequences 递推+树状数组

来源:互联网 发布:阿凡达妹妹唱功知乎 编辑:程序博客网 时间:2024/04/30 11:06

题意:

给出n 和 d (2<=n<=100000,1<=d=<=10000000), 定义,任意一个子串,如果满足相邻元素的差不大于d,则称该子串为一个perfect子串,问一共有多少这样的子串,输出ans % mod。

题解:

设dp(i)表示前i个字符中,perfect子串的个数,则dp[i] = sum(dp[j], 0<j<i, |s[j]-s[i]| <= d), 这题的关键点在于如何快速求出sum(),可考虑用树状数组,则,sum(i+d) - sum(i-d-1) 就是答案,可是问题是:1.数字范围很大。2.可能存在负数。解决这两个问题可以考虑用离散化,如何离散化呢?其实我们只需要把dp[i]在树状数组中的位置离散化就行了,只需要定义一个dis[]数组,里面保存的是排序并且去重后的原数组,那么,只需在dis[]数组中进行二分查找即可找到位置了。

细节:

这题有个小陷阱,就是取模的时候,要注意可能为负数。

具体就看代码吧:

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 1e5 + 10;const int MOD = 9901;int arr[maxn], dis[maxn], c[maxn], n, d, cnt;//6 2//-5 -7 0 3 1 2void read_input(){    for (int i = 1; i <= n; i++)    {        scanf("%d", &arr[i]);        dis[i] = arr[i];    }}void dis_cre(){    sort(dis+1, dis+1+n);    cnt = 0;    for (int i = 1; i <= n; i++)    {        if (i != 1 && dis[i] == dis[i-1])        {            dis[cnt] = dis[i];        }        else {            dis[++cnt] = dis[i];        }    }}void init(){    memset(c, 0, sizeof(c));}inline int lowbit(int x) { return x & (-x); }void add(int x, int v){    while (x <= cnt)    {        c[x] += v;        x += lowbit(x);    }}int sum(int x){    int ans = 0;    while (x > 0)    {        ans += c[x];        ans %= MOD;        x -= lowbit(x);    }    return ans;}int bi_search(int v){    int L = 1, R = cnt;    while (L <= R)    {        int M = (L + R) >> 1;        if (dis[M] < v) {            L = M+1;        }        else {            R = M-1;        }    }    if (dis[L] == v) return L;    return R;}void solve(){    int dp = 1, ans = 1, index = bi_search(arr[1]);    add(index, dp);    for (int i = 2; i <= n; i++)    {        index = bi_search(arr[i]);        int L = bi_search(arr[i]-d-1);        int R = bi_search(arr[i]+d);        dp = sum(R) - sum(L) + 1;        if (dp < 0) dp += MOD;        ans += dp;        ans = ans % MOD;        add(index, dp);    }    ans = ((ans-n)%MOD+MOD) % MOD;    printf("%d\n", ans);}int main(){//    freopen("/Users/apple/Desktop/in.txt", "r", stdin);        while (scanf("%d%d", &n, &d) != EOF)    {        init();        read_input();        dis_cre();        solve();    }            return 0;}


0 0
原创粉丝点击