首页 > 其他分享 >hdu 2227 Find the nondecreasing subsequences (树状数组+dp+离散化)

hdu 2227 Find the nondecreasing subsequences (树状数组+dp+离散化)

时间:2023-07-18 19:35:19浏览次数:42  
标签:hdu 树状 int 2227 ll mid subsequences 数组 dp


题意:给定一个长度为n(n <= 100000)的整数序列,求其中的递增序列的个数。


对于某些序列中的递增序列的个数是可以用dp来求解的,其状态转移方程为:

dp[i] = sum(dp[j]) + 1,j < i &&a[j] < a[i]

根据状态转移方程可以得知这样dp的时间复杂度为O(n^2),而对于题目给定的10^6的数量级来说,这样dp是不行的。

那么我们根据a[j]<a[i],可以得知,这其实就是逆序对,而求逆序对的快速方法莫过于树状数组了。

因此我们想到了树状数组,而对于题目给的a[i]元素的大小,a[i] <= 2^31,这样的数量级,很显然直接将其应用到树状数组是不可能的。

我们发现总共的元素只有n <= 10^6 个,而a[i]的最大值可以达到2^31,所以我们为了能够应用树状数组,我们想到了离散化。

离散化:我们将a[i]从小到大排个序,并将重复的元素去掉只留下一个,那么我们可以得出,每个a[i]都能对应一个数组下标,而我们就利用这个数组下标来建立树状数组。

这样在树状数组增加值的时候我们就根据dp原理,利用树状数组的性质,完成了对后面的所有元素进行求和的运算,那么最后的出来的结果就是我们要求的结果了。


下面附上代码,上面带上解释:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

#define N 100001
#define ll long long
#define Lowbit(x) ((x)&(-x))
#define M 1000000007
ll C[N];
ll num[N], t[N];
int T,tot;


void add(ll C[],ll pos,ll num) {
    while(pos <= N) {//x×î´óÊÇN
        C[pos] += num;
        if(C[pos] > M)C[pos] %= M;
        pos += Lowbit(pos);
    }
}

ll Sum(ll C[],ll end) {
    ll sum = 0;
    while(end > 0) {
        sum += C[end];
        if(sum > M)sum%= M;
        end -= Lowbit(end);
    }
    return sum;
}

int binarysearch(int x){//二分查找下标
    int mid, l = 1 ,r = tot;
    while(l <= r){
        mid = (l + r)>>1;
        if(x == t[mid])return mid;
        else if(x > t[mid]){
            l = mid + 1;
        }
        else r = mid - 1;

    }
    return -1;
}

int main() {
    int n, s,  i, j, T, k, m;
    ll ans, tmp;
    while(~scanf("%d",&T)) {
        ans = 0;
        for(i = 0; i < T; i ++) {
            scanf("%I64d",&num[i]);
            t[i+1] = num[i];
        }
        sort(t+1,t+1+T);//开始离散化
        tot = 1;
        C[tot] = 0;
        for(i = 2; i <= T; i++){//去重
            if(t[ i ] != t[i - 1]){
                t[++tot] = t[i];
                C[tot] = 0;
            }
        }
        for(i = 0; i < T; i ++){//将原来的数更改为其对应的数组下标
            num[i] = binarysearch(num[i]);
        }
        ans = 0;
        add(C,1,1);//因为每个元素都要加一个自己,所以先将所有的元素加一
        for(i = 0; i < T; i++){
            m = Sum(C,num[i]);//求出其前面有多少个小于它的数,
            ans += m; if(ans > M)ans %= M;//加起来,取模
            add(C,num[i],m);//将其值加进树状数组,原理为dp思想。
        }

        printf("%I64d\n",ans);
    }
    return 0;
}




标签:hdu,树状,int,2227,ll,mid,subsequences,数组,dp
From: https://blog.51cto.com/u_16192154/6767461

相关文章

  • hdu Polynomial Problem
     有点杂乱无章,考虑各种情况就行了。 #include<iostream>#include<cstdio>#include<cstring>#include<cmath>usingnamespacestd;#defineINF0x3fffffff#defineMAXN100001intmain(){intn,m,x,flag,mul,ans;charstr[MAXN];whil......
  • hdu 1010 Tempter of the Bone (dfs+奇偶剪枝)
    小记:最开始以为是T时间内,用bfsWA了,后来知道是刚好T时间,然后就用dfs,相当于暴力了,然后简单的dfs提交TLE,必须剪枝。首先判最少需要的时间是否有,没有就不用继续了,而如果有,那么因为我们是要花掉T时间刚好到达,那么我们先保证能走到终点的时间,然后在路上花掉多余的时间此时,我们必须保证......
  • 题解 HDU5726【GCD】/ LGT353762【Soso 的最大公约数】
    Problem给你一个长为\(N(1\leqN\leq1\times10^5)\)的整数序列:\(a_{1},\cdots,a_{n}(0<a_{i}\leq1\times10^9)\)。有\(Q(1\leqQ\leq1\times10^5)\)次提问。每次提问有个范围\(l,r\),你需要计算出\(\gcd(a_{l},,a_{l+1},...,a_{r})\),并且统计数对\((l’,r’......
  • 【CF1621G】Weighted Increasing Subsequences 题解(优化树状数组)
    CF传送门|LG传送门。优化树状数组+反向处理。Solution发现直接做不好下手。难点主要在求出所有的上升子序列并计算它们分别的贡献。所以需要反向考虑每个单点在什么情况下产生贡献。一个单点会产生多少贡献。一个单点产生贡献的条件很容易得到。一个是在一个上升子序......
  • hdu 2604(矩阵快速幂)
    题意:f和m两种字母,给出l表示有2^l个由f和m组成长度为l的字符串,如果这些字符串内包含fmf或fff子串的是一种特殊字符串,给出l问不是特殊字符串的数量是多少。题解:先暴力把前几个l的答案跑了一下,发现有个规律f(n)=f(n-1)+f(n-3)+f(n-4),试着用这个公式写了矩阵快速幂交上去......
  • hdu 1575(矩阵快速幂)
    题解:矩阵快速幂模板题。#include<stdio.h>#include<string.h>constintN=10;structMat{intg[N][N];}res,ori;intn,k;Matmultiply(Matx,Maty){Mattemp;memset(temp.g,0,sizeof(temp.g));for(inti=0;i<n;i++)......
  • hdu 5249(set + queue)
    题意:Input有大约100组数据。每组数据第一行有一个n(1≤n≤10000),代表服务记录数。接下来有n行,每一行有3种形式“inx”:代表重要值为x(0≤x≤109)的请求被推进管道。“out”:代表服务拉取了管道头部的请求。“query:代表我想知道当前管道内请求重要值的中间值.那就是......
  • hdu 5256(最长上升子序列)
    题意:我们有一个数列A1,A2…An,你现在要求修改数量最少的元素,使得这个数列严格递增。其中无论是修改前还是修改后,每个元素都必须是整数。请输出最少需要修改多少个元素。题解:这是一个很机智的想法,每个数字和它的对应位置的差值存到数组s中,n-s序列的最长上升子序列就是解。#incl......
  • hdu 3117(矩阵快速幂)
    题意:求斐波那契序列的第n个数。如果超过8位,只输出前4位和后4位。题解:后4位比较好办,直接mod10000就可以了,前4位不知道怎么求,网上看到一个人写的很详细易懂,需要用到斐波那契通项公式,详细见→传送门#include<stdio.h>#include<math.h>#include<string.h>structMat{long......
  • hdu 5254(暴力)
    题解:暴力所有点,直到不存在可以0变1的点。#include<stdio.h>#include<string.h>constintN=505;intn,m,k,g[N][N],temp[N][N],vis[N][N];booljudge(intx,inty){if(x-1>=0&&y-1>=0){if(temp[x-1][y]&&te......