题意:
找出所有的美丽序列。美丽序列就是相邻的元素绝对值之差不超过d的序列。
分析:
dp[i]表示到i为止满足情况的种类数。
dp[i]=sum(dp[j] abs(a[j]-a[i])<=d);
当然这个数据量很大,直接按照方程的话复杂度为O(n*n). 所以要利用其他方式,树状数组。这里需要对元素离散化,因为d很大。刚开始想的时候以为二维的DP可以,但是存储空间不允许。后来一直不明白的问题是如何证明:
dp[i]=sum(dp[j] abs(a[j]-a[i])<=d);
假如 1 3 5 7 满足序列,那么美丽序列就有{1,3}{3,5}{5,7}{1,3,5}{3,5,7}{1,3,5,7} 分别为两个元素的情况,三个元素的情况,四个元素的情况。当然我们数的时候会这样想,但是计算的时候就不能这样想了。首先加入树状数组之前,先求出满足条件的种类数,那么这个数就要加入到这些合法的序列后面才合法,而这些合法的序列的由来又有很多种方式+1(只有自己),所以结果还是递推出来的。
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<utility>
#include <map>
#include<cstring>
#include<vector>
#include<deque>
#include<queue>
#include<stack>
#include<algorithm>
#include<stdlib.h>
#define read freopen("q.txt","r",stdin)
#define LL long long
const int maxn =100005;
const double inf=2000000000.0;
const int mod=9901;
using namespace std;
int c[maxn],a[maxn],hs[maxn];
int cnt,n;
int lowbit(int x)
{
return x&(-x);
}
int getSum(int x)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
{
sum+=c[i];
sum%=mod;
}
return sum;
}
void update(int x,int val)
{
for(int i=x;i<=n;i+=lowbit(i))
{
c[i]+=val;
}
}
int low(int x)
{
int l=1,r=cnt;
while(l<=r)
{
int mid=(l+r)/2;
if(hs[mid]<x)l=mid+1;
else r=mid-1;
}
return r+1;
}
int up(int x)
{
int l=1,r=cnt;
while(l<=r)
{
int mid=(l+r)/2;
if(hs[mid]<=x)l=mid+1;
else r=mid-1;
}
return l-1;
}
int main()
{
int d,i,j;
while(~scanf("%d%d",&n,&d))
{
memset(c,0,sizeof(c));
for(i=1;i<=n;i++)
{
scanf("%d",a+i);
hs[i]=a[i];
}
sort(hs+1,hs+n+1);
cnt=1;
for(i=2;i<=n;i++)if(hs[i]!=hs[cnt])hs[++cnt]=hs[i];
int sum=0;
for(i=1;i<=n;i++)
{
int x=low(a[i]-d),y=up(a[i]+d),z=low(a[i]);
int tmp=getSum(y)-getSum(x-1);
tmp+=mod;
tmp%=mod;
/// cout<<"TTTTmp = "<<tmp<<endl;
sum=(sum+tmp)%mod;
update(z,tmp+1);
// cout<<"sum = "<<sum<<endl;
}
cout<<sum<<endl;
}
}