• 小沙的remake(竞速版)题解(乱序dp+树状数组)


    题目链接

    题目思路

    一个简单的想法就是设\(dp[i]\)表示以\(i\)结尾的答案

    那么转移就是找\([i-b[i],i-1]\)中所有\(a[j]<a[i]\)的值\(dp[i]+=dp[j]\)

    最后\(dp[i]++\) 表示以\(i\)开头,那么转移就是找一个区间中大于一个数的所有\(dp\)值之和\(+1\)

    那么不就是主席树吗

    但是可以进行优化,可以不要从后往前\(dp\),而是按照\(a[i]\)的大小排序进行\(dp\)

    按照权值的大小从小到大插入选取该点的方案数到对应下标上,所以的话对于权值比你大的点,你没有进行计算,

    且求和过程中可以计算区间的和。全部插入之后输出1~n的和即可。

    相对于传统的DP,这里使用的是一种相对乱序的DP转移方式

    代码

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define ll long long
    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;
    const int N=2e6+7,mod=1e9+7;
    int a[N],b[N];
    pair<int,int> pa[N];
    int n,seed;
    ll f[N];
    int query(int x){
        int res=0;
        while(x) (res+=f[x])%=mod,x-=x&-x;
        return res;
    }
    void add(int x,int y){
        while(x<=n) (f[x]+=y)%=mod,x+=x&-x;
    }
    int main(){
        scanf("%d %d",&n,&seed);
    	srand(seed);
    	for(int i=1;i<=n;i++){
    		a[i]=read(0),b[i]=read(i);
    		pa[i]={a[i],i};
    	}
        sort(pa+1,pa+1+n);
        ll pr=0;
        for(int i=1;i<=n;i++){
            ll tmp=query(pa[i].se)-query(max(0,pa[i].se-b[pa[i].se]-1))+1;
            tmp=(tmp%mod+mod)%mod;
            add(pa[i].se,tmp);
            pr=(pr+tmp)%mod;
        }
        printf("%lld\n",pr);
        return 0;
    }
    
    
  • 相关阅读:
    c++类中比较重要的几个函数
    rosbag使用方法
    2.urllib库的使用
    什么叫做API?
    1.爬虫基础
    正则表达式

    time模块
    random模块
    日志处理
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/15849432.html
Copyright © 2020-2023  润新知