题目
原题链接
问题描述
给定
    
     
      
       
        n
       
       
        (
       
       
        1
       
       
        ≤
       
       
        n
       
       
        ≤
       
       
        2
       
       
        ∗
       
       
        1
       
       
        
         0
        
        
         6
        
       
       
        )
       
      
      
       n(1\leq n\leq2∗10^6)
      
     
    n(1≤n≤2∗106)和
    
     
      
       
        s
       
       
        e
       
       
        e
       
       
        d
       
      
      
       seed
      
     
    seed,将基于
    
     
      
       
        s
       
       
        e
       
       
        e
       
       
        d
       
      
      
       seed
      
     
    seed生成两个长度为
    
     
      
       
        n
       
      
      
       n
      
     
    n的序列
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai和
    
     
      
       
        
         b
        
        
         i
        
       
       
        (
       
       
        0
       
       
        ≤
       
       
        
         b
        
        
         i
        
       
       
        <
       
       
        i
       
       
        )
       
      
      
       b_i(0\leq b_i<i)
      
     
    bi(0≤bi<i)。
 我们的任务就是从序列
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai中依照规则进行选择,问我们有多少种选择策略,结果对
    
     
      
       
        1
       
       
        e
       
       
        9
       
       
        +
       
       
        7
       
      
      
       1e9+7
      
     
    1e9+7取模。
 规则有两条,
 第一:我们选择的
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai不能小于上一次选择的元素。
 第二:若要选择
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai,需要保证在序列段
    
     
      
       
        
         a
        
        
         
          (
         
         
          i
         
         
          −
         
         
          
           b
          
          
           i
          
         
         
          )
         
        
       
      
      
       a_{(i-b_i)}
      
     
    a(i−bi)和
    
     
      
       
        
         a
        
        
         
          i
         
         
          −
         
         
          1
         
        
       
      
      
       a_{i-1}
      
     
    ai−1之间存在被选择过的元素,否则不能选择
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai。
 
分析
朴素思路
直接进行DP
    dp[1]=1;
	for(int i=2;i<=n;i++){
        dp[i]=dp[i-1]+1;
		for(int j=i-1;j>=i-b[i];j--){
			if(a[i]>=a[j]){
				(dp[i]+=dp[j]-dp[j-1])%mod;
			}
		}
	}
状态
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        ]
       
      
      
       dp[i]
      
     
    dp[i]表示长度为
    
     
      
       
        i
       
      
      
       i
      
     
    i的序列的方案数,边界条件为
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        1
       
       
        ]
       
       
        =
       
       
        1
       
      
      
       dp[1]=1
      
     
    dp[1]=1,也就是只有一个元素时方案数为
    
     
      
       
        1
       
      
      
       1
      
     
    1。
 对于
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        ]
       
      
      
       dp[i]
      
     
    dp[i],首先
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        ]
       
       
        =
       
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        −
       
       
        1
       
       
        ]
       
       
        +
       
       
        1
       
      
      
       dp[i]=dp[i-1]+1
      
     
    dp[i]=dp[i−1]+1,也就是在
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        −
       
       
        1
       
       
        ]
       
      
      
       dp[i-1]
      
     
    dp[i−1]的基础上,考虑一种只选择元素
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai的情况;
 之后,考虑在选择了元素
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai的基础上,与前序元素的承接,如果在区间
    
     
      
       
        [
       
       
        
         a
        
        
         
          i
         
         
          −
         
         
          b
         
         
          [
         
         
          i
         
         
          ]
         
        
       
       
        ,
       
       
        
         a
        
        
         
          i
         
         
          −
         
         
          1
         
        
       
       
        ]
       
      
      
       [a_{i-b[i]},a_{i-1}]
      
     
    [ai−b[i],ai−1]中,存在元素
    
     
      
       
        
         a
        
        
         j
        
       
      
      
       a_j
      
     
    aj小于等于
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai,那么
    
     
      
       
        (
       
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        ]
       
       
        +
       
       
        =
       
       
        d
       
       
        p
       
       
        [
       
       
        j
       
       
        ]
       
       
        −
       
       
        d
       
       
        p
       
       
        [
       
       
        j
       
       
        −
       
       
        1
       
       
        ]
       
       
        )
       
       
        %
       
       
        m
       
       
        o
       
       
        d
       
      
      
       (dp[i]+=dp[j]-dp[j-1])\%mod
      
     
    (dp[i]+=dp[j]−dp[j−1])%mod,
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        ]
       
      
      
       dp[i]
      
     
    dp[i]要加上
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        j
       
       
        ]
       
       
        −
       
       
        d
       
       
        p
       
       
        [
       
       
        j
       
       
        −
       
       
        1
       
       
        ]
       
      
      
       dp[j]-dp[j-1]
      
     
    dp[j]−dp[j−1]。
 所谓的承接就是在这种情况下同时选择了
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai和
    
     
      
       
        
         a
        
        
         j
        
       
      
      
       a_j
      
     
    aj,但
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        j
       
       
        ]
       
      
      
       dp[j]
      
     
    dp[j]中包含了选择
    
     
      
       
        
         a
        
        
         j
        
       
      
      
       a_j
      
     
    aj和没有选择
    
     
      
       
        
         a
        
        
         j
        
       
      
      
       a_j
      
     
    aj的情况,所以要用
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        j
       
       
        ]
       
       
        −
       
       
        d
       
       
        p
       
       
        [
       
       
        j
       
       
        −
       
       
        1
       
       
        ]
       
      
      
       dp[j]-dp[j-1]
      
     
    dp[j]−dp[j−1]。
但很明显可以看出,这种方法的时间复杂度为 O ( n 2 ) O(n^2) O(n2),会超时,所以我们不使用这种方法。
树状数组+优化DP
之前朴素DP不理想的原因是进行了双重循环,所以时间复杂度为
    
     
      
       
        O
       
       
        (
       
       
        
         n
        
        
         2
        
       
       
        )
       
      
      
       O(n^2)
      
     
    O(n2),会超时,那么我们接下来的思路就是对这个循环进行优化。
 在第二重循环中,我们的工作是依次访问区间
    
     
      
       
        [
       
       
        
         a
        
        
         
          (
         
         
          i
         
         
          −
         
         
          
           b
          
          
           i
          
         
         
          )
         
        
       
       
        ,
       
       
        
         a
        
        
         
          i
         
         
          −
         
         
          1
         
        
       
       
        ]
       
      
      
       [a_{(i-b_i)},a_{i-1}]
      
     
    [a(i−bi),ai−1]中的元素,正是因为我们此时无法得知在这个区间中的大小情况,所以才需要依次访问,如果我们可以直接得知这一区间的情况就可以优化循环。
树状数组小结——>求逆序对数
 求逆序对数是一道经典例题,解法多样,用树状数组解法时的思路与这道题有类似的地方,可以借鉴一下。
我们定义状态
     
      
       
        
         d
        
        
         p
        
        
         [
        
        
         i
        
        
         ]
        
       
       
        dp[i]
       
      
     dp[i]为以
     
      
       
        
         
          a
         
         
          i
         
        
       
       
        a_i
       
      
     ai作为最后一个元素的选择方案数。
 再对序列
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai依照大小进行从小到大的排序,然后依照大小依次处理,将其依次插入到
    
     
      
       
        d
       
       
        p
       
      
      
       dp
      
     
    dp数组中,每次处理时就不必依次访问区间
    
     
      
       
        [
       
       
        
         a
        
        
         
          i
         
         
          −
         
         
          b
         
         
          [
         
         
          i
         
         
          ]
         
        
       
       
        ,
       
       
        
         a
        
        
         
          i
         
         
          −
         
         
          1
         
        
       
       
        ]
       
      
      
       [a_{i-b[i]},a_{i-1}]
      
     
    [ai−b[i],ai−1]中的元素。
以
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        ]
       
      
      
       dp[i]
      
     
    dp[i]为例,
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        ]
       
       
        =
       
       
        1
       
       
        +
       
       
        
         ∑
        
        
         
          k
         
         
          =
         
         
          i
         
         
          −
         
         
          
           b
          
          
           i
          
         
        
        
         
          i
         
         
          −
         
         
          1
         
        
       
       
        d
       
       
        p
       
       
        [
       
       
        k
       
       
        ]
       
      
      
       dp[i]=1+\sum_{k=i-b_i}^{i-1}dp[k]
      
     
    dp[i]=1+∑k=i−bii−1dp[k]
 由于我们是采用从小到大的处理顺序,所以区间中出现
    
     
      
       
        
         a
        
        
         k
        
       
       
        >
       
       
        
         a
        
        
         i
        
       
      
      
       a_k>a_i
      
     
    ak>ai时,对应的
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        k
       
       
        ]
       
      
      
       dp[k]
      
     
    dp[k]还是
    
     
      
       
        0
       
      
      
       0
      
     
    0,所以此时实际相加的还是元素值小于等于
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai的情况。
最后输出整个数组的和就是我们最后的解。
由于过程中需要频繁的求区间和,所以要借助树状数组来优化时间,当然了,用其他可以处理RMQ问题的方法同样可以优化时间。
 ST表,处理静态RMQ,虽然可以处理RMQ,但由于更新操作过多,所以不适合;
 线段树,处理一般RMQ,值得一试。
代码
#include<bits/stdc++.h>
namespace GenHelper
{
    int z1,z2,z3,z4,z5,u,res;
    int get()
    {
        z5=((z1<<6)^z1)>>13;
        z1=((int)(z1&4294967)<<18)^z5;
        z5=((z2<<2)^z2)>>27;
        z2=((z2&4294968)<<2)^z5;
        z5=((z3<<13)^z3)>>21;
        z3=((z3&4294967)<<7)^z5;
        z5=((z4<<3)^z4)>>12;
        z4=((z4&4294967)<<13)^z5;
        return (z1^z2^z3^z4);
    }
    int read(int m) {
        u=get();
        u>>=1;
        if(m==0)res=u;
        else res=(u/2345+1000054321)%m;
        return res;
    }
     void srand(int x)
    {
        z1=x;
        z2=(~x)^(0x23333333);
        z3=x^(0x12345798);
        z4=(~x)+51;
      	u = 0;
    }
}
using namespace GenHelper;
using namespace std;
typedef long long ll;
const int N=2e6+7,mod=1e9+7;
int a[N],b[N],n;
int dp[N];
pair<int,int>p[N];
void update(int i , int k) {
	while(i<=n)dp[i]=(dp[i]+k)%mod,i+=i&-i;
}
int getsum(int i){
	int sum=0;
    if(i<=0)return 0;
    while(i)sum=(sum+dp[i])%mod,i -= i&-i;
    return sum;
}
int main(){
    int seed;
    scanf("%d %d",&n,&seed);
	srand(seed);
	for(int i=1;i<=n;i++){
		a[i]=read(0),b[i]=read(i);
		p[i].first=a[i],p[i].second=i;
	}
	sort(p+1,p+1+n);
	for(int i=1;i<=n;++i){
		int k=p[i].second;
		int tmp=(getsum(k-1)-getsum(k-b[k]-1)+1+mod)%mod;
		update(k,tmp);
	}
	cout<<getsum(n);
    return 0;
}










