小沙的remake(普通版)

tag:

  • 线段树,树状数组,dp
  • cf分段1800+

两个题就一起讲了:

找到连续的,上升子序列且下标之差满足某个范围
求方案数

题目挺简单的,特别是你如果马上能利用dp计数方案的思维去思考这题,就会立马发现这题首先要做的一点就是存储下标+排序

排序完了之后就是寻找当数字之前且下标也在他之前的方案数量,存储到当前数字的下标的数组里。

这个维护手段就是树状数组,所以如果能把dp和树状数组结合起来,这题就是秒切了。

#include<bits/stdc++.h>
using namespace std;

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;

const int N=2e6+7,mod=1e9+7;
int a[N],b[N];
pair<int,int>x[N];
#define ll long long
ll tre[N];
int lowbit(int x){
    return x&(-x);
}
int n;
void add(int x,int k){
    while(k<=n){
        tre[k]= (tre[k] + x) % mod;
        k+=lowbit(k);
    }
}
ll getsum(int k){
    ll sum = 0;
    while(k){
        sum=(tre[k] + sum ) % mod;
        k-=lowbit(k);
    }
    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);
        x[i].first = a[i];
        x[i].second = i;
	}
    sort(x+1,x+n+1);
    ll sum = 0;
    for(int i = 1 ; i<= n ; i++) {
        ll kmm = (getsum(x[i].second) - getsum(x[i].second - b[x[i].second] - 1) + 1 + mod) % mod;
        add(kmm,x[i].second);
    }
    cout<<getsum(n);
    return 0;
}