题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5542
题目大意:在n个数中找长度为m的单调上升子序列有多少种方案
题目思路:DP,离散化,树状数组优化,
dp[i][j]代表大小为i的数 长度为j时的方案,状态转移方程dp[i][j]=simiga(dp[1..i-1][j-1]) 如果直接求和的话,复杂度是n^3不行
用树状数组优化求和 复杂度n^2logn
n<=1000,a[i]<=1e9,所以离散化搞一下就行
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=1100; 7 const long long mod=1e9+7; 8 long long tree[maxn][maxn]; 9 long long dp[maxn][maxn]; 10 long long a[maxn],b[maxn]; 11 void add(int i,int m,int k){ 12 for(i;i<=maxn;i+=(i&(-i))) (tree[i][m]+=k)%=mod; 13 } 14 long long query(int i,int m){ 15 long long sum=0; 16 for(i;i>0;i-=(i&(-i))) (sum+=tree[i][m])%=mod; 17 return sum%mod; 18 } 19 void init(){ 20 memset(dp,0,sizeof(dp)); 21 memset(tree,0,sizeof(tree)); 22 } 23 void solve(int T){ 24 printf("Case #%d: ",T); 25 int n,m; 26 scanf("%d %d",&n,&m); 27 init(); 28 for(int i=1;i<=n;i++) scanf("%lld",&b[i]),a[i]=b[i]; 29 sort(b+1,b+1+n); 30 int size=unique(b+1,b+1+n)-b; 31 for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+size,a[i])-b; 32 for(int i=1;i<=n;i++){ 33 for(int j=1;j<=min(i+1,m);j++){ 34 if(j==1) dp[j][a[i]]=1; 35 else 36 dp[j][a[i]]=query(a[i]-1,j-1)%mod; 37 add(a[i],j,dp[j][a[i]]); 38 } 39 } 40 printf("%lld\n",query(size+1,m)%mod); 41 } 42 int main(){ 43 int T; 44 scanf("%d",&T); 45 for(int i=1;i<=T;i++) solve(i); 46 }
时间: 2024-11-02 23:26:12