HDOJ5542 The Battle of Chibi(LIS拓展问题,树状数组优化转移方程)

传送门
题意很简单:给定一个长度为N的序列A,求A有多少个长度为M的严格递增子序列。

先考虑暴力的dp.设dp[i][j]表示的是以i结尾长度为j的LIS的数量.转移方程:
dp[i][j] = sum{dp[k][j-1] 0 <= k < j && a[i] > a[k]}.
代码:

fir(i,1,n){
    
    
    fir(j,1,min(i,m)){
    
    
        fir(k,0,j-1){
    
    
            if(a[i] > a[k]){
    
    
                dp[i][j] += dp[k][j-1];
            }
        }
    }
}

这个算法是n^3的,题目数据是1e3,过不去.考虑优化.
观察转移方程和最内层的循环可以发现的是,待选集合是随着i增大而增大的,这启发我们可以用某种数据结构去优化内层循环.小于a[i]的个数的和这个属性可以用树状数组或者线段树去储存,为了方便我们选择树状数组.
具体做法就是开一个二维的树状数组.c[i][j]第一维表示的是长度.第二维维护权值序列.因为有负数的原因,我们可以选择离散化.
复杂度(O(nmlogn))
代码:

#pragma GCC optimize(2)
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 1e3+10;
const int mod = 1e9+7;

inline void read(int &a){
    
    
    int x = 0,f=1;char ch = getchar();
    while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
    a = x*f;
}
int tt,t,n,m,a[N];
vi all;
LL dp[N][N],c[N][N];
LL ask(int len,int p){
    
    
    LL res = 0;
    for(;p;p-=p&-p) res = (res+c[len][p])%mod;
    return res;
}
void add(int len,int p,int v){
    
    
    for(;p<=tt;p+=p&-p) c[len][p] = (c[len][p] + v)%mod;
}

int getpos(int x){
    
    
    return lower_bound(ALL(all),x) - all.begin();
}
int main(){
    
    
    read(t);
    fir(tot,1,t){
    
    
        printf("Case #%d: ",tot);
        read(n);read(m);
        all.clear();
        all.pb(-2e9);
        all.pb(-2e9+1);
        fir(i,1,n)
            read(a[i]),all.pb(a[i]);
        mem(dp,0);
        mem(c,0);
        dp[0][0] = 1;
        sort(ALL(all));
        all.erase(unique(ALL(all)),all.end());
        tt = all.size();
        fir(i,1,n) a[i] = getpos(a[i]);
        add(0,getpos(-2e9+1),1);
        fir(i,1,n){
    
    
            fir(j,1,min(i,m)){
    
    
                dp[i][j] = (dp[i][j]+ask(j-1,a[i]-1))%mod;
                add(j,a[i],dp[i][j]);
            }
        }
        LL ans = 0;
        fir(i,m,n) ans = (ans+dp[i][m])%mod;
        printf("%lld\n",ans);
    }   
    
    return 0;
}    


/*
    dp[i][j] 表示以i结尾,长度为j的LIS有多少个.
    dp[i][j] = sum{dp[k][j-1] 0 <= k < j && a[i] > a[k]}.

*/

猜你喜欢

转载自blog.csdn.net/weixin_45590210/article/details/108145440
今日推荐