dp+树状数组

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

输入格式

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

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

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

输出格式

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

输出格式为 Case #x: yx 为数据组别序号,从 11 开始,yy 为结果。

由于答案可能很大,请你输出对 1e9+7取模后的结果。

数据范围

1T100
1MN1000
Ti=1Ni×Mi1e7
序列中的整数的绝对值不超过1e9

输入样例:

2
3 2
1 2 3
3 2
3 2 1

输出样例:

Case #1: 3
Case #2: 0



f[maxn][maxn];//以第i个结尾时,有j个递增的方案数
优化之前的代码时这样的:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e3+100;
const int mod=1e9+7;
int a[maxn],t;
int f[maxn][maxn];//以第i个结尾时,有j个递增的方案书 
int n,m;
int main(){
    cin>>t;
    int kase=0;
    while(t--){
        memset(f,0,sizeof(f));
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        f[1][1]=1;
        for(int i=1;i<=n;i++){
            f[i][1]=1;
        }
        for(int i=2;i<=n;i++){
            for(int j=1;j<m;j++){
                for(int k=1;k<i;k++){ 
                    if(a[i]>a[k]){
                        f[i][j+1]+=f[k][j];    
                    }
                    f[i][j+1]%=mod;
                } 
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            //cout<<f[i][m]<<endl;
            ans+=f[i][m];
            ans%=mod; 
        }
        printf("Case #%d: %d\n",++kase,ans);
    } 
    
}

 

然后可以用线段树或者树状数组优化掉一维
#include<iostream>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;
const int maxn=1e3+100;
const int mod=1e9+7;
int a[maxn],t;
int f[maxn][maxn];//以第i个结尾时,有j个递增的方案数 
int n,m;
int cnt=0; 
int c[maxn]; 
int num[maxn];
int lowbit(int x){
    return x&-x;
}
void add(int x,int k){
    for(int i=x;i<=cnt;i+=lowbit(i)){
        c[i]=(c[i]+k)%mod;
    }
}
int getsum(int x){
    int ans=0;
    for(int i=x;i>0;i-=lowbit(i)){
        ans=(ans+c[i])%mod; 
    }
    return ans;
}
int main(){
    cin>>t;
    int kase=0;
    while(t--){
        memset(f,0,sizeof(f));
        cin>>n>>m;
        cnt=0;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            num[++cnt]=a[i];
        }
        sort(num+1,num+cnt+1);
        cnt=unique(num+1,num+cnt+1)-(num+1); 
        for(int i=1;i<=n;i++){
            a[i]=lower_bound(num+1,num+cnt+1,a[i])-num;
        }
        for(int i=1;i<=n;i++){
            f[i][1]=1;
        }
        for(int j=2;j<=m;j++){
            for(int i=1;i<=cnt;i++){
                c[i]=0;
            } 
            for(int i=1;i<=n;i++){
                f[i][j]=getsum(a[i]-1);
                add(a[i],f[i][j-1]);
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            ans+=f[i][m];
            ans%=mod; 
        }
        printf("Case #%d: %d\n", ++kase,ans);
    }
} 

 

 


posted @ 2021-03-14 19:27  lipu123  阅读(66)  评论(0编辑  收藏  举报