题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4991
3 2 1 1 2 7 3 1 7 3 5 9 4 8
2 12
思路: dp[i][j]表示一第i个数结尾,长度为j的序列的个数;
那么状态转移方程式:dp[i][j]=sum(dp[k][j-1]);(k<i&&a[i]>a[k])
如果直接遍历,那么时间复杂度至少是O(n*n),超时,所以考虑用树状数组维护一段区间的和;
#include <iostream> #include <stdio.h> #include <string> #include <string.h> #include <cstdio> #include <cmath> #include <algorithm> typedef long long ll; const int mod=123456789; using namespace std; ll a[10100],b[10100],c[10100],dp[10100][110]; int n,m; int lowbit(int t) { return t&(-t); } void modify(int t,ll d) { while(t<=n) { c[t]+=d; t+=lowbit(t); } } ll getsum(int t) { ll ans=0; while(t>0) { ans=(ans+c[t])%mod; t-=lowbit(t); } return ans; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=n;i++) { scanf("%I64d",&a[i]); b[i]=a[i]; } sort(b+1,b+1+n); memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++)dp[i][1]=1; for(int j=2;j<=m;j++) { memset(c,0,sizeof(c)); for(int i=1;i<=n;i++) { int indx=lower_bound(b+1,b+1+n,a[i])-b; dp[i][j]=getsum(indx-1); modify(indx,dp[i][j-1]); } } ll cnt=0; for(int i=1;i<=n;i++) { cnt=(cnt+dp[i][m])%mod; } printf("%I64d\n",cnt%mod); } return 0; }
原文地址:http://blog.csdn.net/liusuangeng/article/details/39181033