hdu 3450 Counting Sequences 遞推+樹狀數組

題意:

給出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 2
void 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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章