zoukankan      html  css  js  c++  java
  • 赤壁之战

    题目连接:

    https://www.acwing.com/problem/content/299/

    Description

    给定一个长度为N的序列A,求A有多少个长度为M的严格递增子序列。

    Input

    第一行包含整数T,表示共有T组测试数据。

    每组数据,第一行包含两个整数N和M。

    第二行包含N个整数,表示完整的序列A。

    Output

    每组数据输出一个结果,每个结果占一行。

    输出格式为“Case #x: y”,x为数据组别序号,从1开始,y为结果。

    由于数据可能很大,请你输入对(10^9+7)取模后的结果。

    Sample Input

    2
    3 2
    1 2 3
    3 2
    3 2 1

    Sample Output

    Case #1: 3
    Case #2: 0

    Hint

    数据范围
    (1≤T≤100, 1≤M≤N≤1000, N×M的和小于10^7)
    序列中的整数的绝对值不超过(10^9)

    题意

    在长度为n的序列中求长度为m的严格递增子序列的个数

    题解:

    首先考虑二维DP,f[i][j]表示前i个且第i个作为最后一个数的长度为j的严格递增子序列个数,f[i][j]+=f[k][j-1](k<i & a[k]<a[i]) DP可以写成

    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            for(int k=1;k<i;++k)
                f[i][j]+=f[k][j-1]
    

    复杂度O(1e10)了,我们需要降掉一维,或者变成n变logn的复杂度。
    第三层循环我们需要找到k<i且a[k]<a[i]的所有f[k][j]的和,即在a[i]之前的和,这样很容易想到用树状数组点插入的做法了,在算第j维时,求j-1维在树状数组中a[i]点之前的前缀和,可以维护一个m维的树状数组。实际上,我们每次只需要j的上一维的树状数组,把第一第二层循环交换一下,就只用维护一个一维的树状数组,每次用完清空,也只用一维的f[i]记录上一维的f[i][j-1]。先更新j-1维的f[i]更新到a[i],再用f[i]的存a[i]-1之前的f[k][j-1]的和即得f[i][j]。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1010,mod=1e9+7;
    int f[N],tr[N],a[N],b[N];
    inline int lowbit(int x) {
        return x&(-x);
    }
    void add(int x,int y){
        while(x<N){
            (tr[x]+=y)%=mod;
            x+=lowbit(x);
        }
    }
    int sum(int x){
        int res=0;
        while(x>0){
            (res+=tr[x])%=mod;
            x-=lowbit(x);
        }
        return res;
    }
    int main(){
        int T;
        cin>>T;
        for(int cas=1;cas<=T;++cas){
            int n,m;
            cin>>n>>m;
            for(int i=1;i<=n;++i){
                cin>>a[i];
                b[i]=a[i];
            }
            sort(b+1,b+1+n);
            int tot=unique(b+1,b+1+n)-b;
            for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
            for(int i=1;i<=n;++i) f[i]=1;
            for(int i=2;i<=m;++i){
                for(int j=1;j<=tot;++j) tr[j]=0;
                for(int j=1;j<=n;++j){
                    add(a[j],f[j]);
                    f[j]=sum(a[j]-1);
                }
            }
            int res=0;
            for(int i=1;i<=n;++i) (res+=f[i])%=mod;
            cout<<"Case #"<<cas<<": "<<res<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    TSQL--NESTED LOOPS JOIN
    TSQL--SORT MERGE JOIN
    TSQL--HASH JOIN
    Backup--备份相关的信息查看及小技巧
    java后台json如何传递到jsp中解析
    大数据资源
    oracle sql生成日历表
    easyUI中onLoadSuccess方法获取多个对象
    征信用户数据分析
    JS优秀资源站点收集
  • 原文地址:https://www.cnblogs.com/jjl0229/p/12682857.html
Copyright © 2011-2022 走看看