HDU - 3450 - Counting Sequences (线段树|树状数组 + 离散化)

Problem Description
or a set of sequences of integers{a1,a2,a3,…an}, we define a sequence{ai1,ai2,ai3…aik}in which 1<=i1<i2<i3<…<ik<=n, as the sub-sequence of {a1,a2,a3,…an}. It is quite obvious that a sequence with the length n has 2^n sub-sequences. And for a sub-sequence{ai1,ai2,ai3…aik},if it matches the following qualities: k >= 2, and the neighboring 2 elements have the difference not larger than d, it will be defined as a Perfect Sub-sequence. Now given an integer sequence, calculate the number of its perfect sub-sequence.
Input
Multiple test cases The first line will contain 2 integers n, d(2<=n<=100000,1<=d=<=10000000) The second line n integers, representing the suquence
Output
The number of Perfect Sub-sequences mod 9901
Sample Input
4 2
1 3 7 5
Sample Output
4

仔细读题啊啊啊啊啊啊啊啊啊啊,因为没多次输入wa了好久。。。
有一个由n个数构成的序列,求其中有几个完美子序列。
完美子序列要满足相邻两元素之差不大于d,且序列中元素不少于两个
思路:
遍历序列中的每一个元素,求出以该元素为末尾元素的完美子序列个数。
假设该元素值为k,则以该元素为末尾元素的完美子序列个数 = 该元素前值在[k-d,k+d]区间内的元素个数 + 以这些元素为末尾元素的完美子序列个数
然后前面的个数已经求过了,就可以直接用,用区间求和,然后更新就行了,就是用线段树或树状数组
因为d比较大,然后元素大小也没有说明,所以就用离散化处理一下

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define N 100050
using namespace std;
typedef long long ll;
int c[N],L[N],R[N];
int a[N],b[N],sum1[N],sum2[N];
int n,tot;
int dd;
void read_discrete(){//读入数据并完成离散化

    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    tot=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++){
        c[i]=lower_bound(b+1,b+tot+1,a[i])-b;
        L[i]=lower_bound(b+1,b+tot+1,a[i]-dd)-b-1;//下界减一
        R[i]=lower_bound(b+1,b+tot+1,a[i]+dd)-b;//上界
        if(R[i]>tot||b[R[i]]>a[i]+dd) R[i]--;
    }

}
int lowbit(int x){

    return x&-x;
}
void add1(int x,int v){
    while(x<=tot){
        sum1[x]+=v;
        sum1[x]%=9901;
        x+=lowbit(x);

    }

}
void add2(int x,int v){
    while(x<=tot){
        sum2[x]+=v;
        sum2[x]%=9901;
        x+=lowbit(x);

    }
}
int  ask1(int x){
    int ans=0;
    while(x>0){
        ans+=sum1[x];
        ans%=9901;
        x-=lowbit(x);
    }
    return ans;
}
int ask2(int x){
    int ans=0;
    while(x>0){

        ans+=sum2[x];
        ans%=9901;
        x-=lowbit(x);
    }
    return ans;
}
int main(){
    while(cin>>n>>dd){
    read_discrete();
    memset(sum1,0,sizeof(sum1));
    memset(sum2,0,sizeof(sum2));
    int temp;
    for(int i=1;i<=n;i++)
    {

        temp=ask1(R[i])-ask1(L[i])+ask2(R[i])-ask2(L[i]);
        temp=(temp+9901)%9901;
        add1(c[i],1);
        add2(c[i],temp);
    }

    cout<<ask2(tot)%9901<<endl;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轩辕青山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值