1. 程式人生 > 實用技巧 >《演算法競賽進階指南》0x58資料結構優化DP HDOJ5542

《演算法競賽進階指南》0x58資料結構優化DP HDOJ5542

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5542

求一個長度為n的序列的長度為m的嚴格上升子序列的數量,dp的狀態是前i個數中長度為j的嚴格上升子序列且以第i個數結尾的決策數量。

轉移方式:長度為i-1向長度為i轉移,列舉位置比它小而且值比它小的決策的數量,通過樹狀陣列將一個維度優化成為O(logn)級別,最終時間複雜度大約是O(n*mlogn)。

處理這樣決策集合只會增大並且只會有一個候選項加到決策集合中的問題,可以用樹狀陣列代表一個位置變數,然後一個維度線性增長,每次新增進一個目標值,這樣就可以查詢前i個目標值中不超過給定值的字首和。

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1010,mod=1e9+7;
int c[N];
int a[N];
int num[N];
int cnt,n,m;
int f[N][N];

int lowbit(int x){
    return x & -x;
}
int query(int x){
    int ans=0;
    while(x){
        ans
=(ans+c[x])%mod; x-=lowbit(x); } return ans; } void update(int x,int C){ while(x<=cnt){ c[x]=(c[x]+C)%mod; x+=lowbit(x); } } int main(){ int T; cin>>T; for(int C=1;C<=T;C++){ cin>>n>>m; for(int i=1;i<=n;i++)scanf("
%d",&a[i]); //離散化 memcpy(num,a,sizeof(a)); sort(num+1,num+n+1); cnt=unique(num+1,num+n+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++){ memset(c,0,sizeof c); for(int i=1;i<=n;i++){ f[i][j]=query(a[i]-1);//小於a[i]的字首和 update(a[i],f[i][j-1]); } } int ans=0; for(int i=1;i<=n;i++) ans=(ans+f[i][m])%mod; printf("Case #%d: %d\n",C,ans); } return 0; }