#include<stdio.h> #include<string.h> #include<ctype.h> #include<math.h> #include<iostream> #include<string> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);} #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;} template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;} const int N=1e5+10,M=0,Z=1e9+7,ms63=1061109567; int casenum,casei; int n,m,x; struct BIT { LL f[N]; void add(int x,LL v) { for(;x<=n;x+=x&-x)f[x]+=v; } LL cnt(int x) { LL tmp=0; for(;x;x-=x&-x)tmp+=f[x]; return tmp; } }bit[12]; int main() { while(~scanf("%d%d",&n,&m)) { ++m; MS(bit,0); LL ans=0; for(int i=1;i<=n;++i) { scanf("%d",&x); bit[1].add(x,1); if(m==1)++ans; for(int j=2;j<=m;++j) { LL tmp=bit[j-1].cnt(x-1); bit[j].add(x,tmp); if(m==j)ans+=tmp; } } printf("%lld\n",ans); } return 0; } /* 【题意】 给你n(1e5)个数a[],每个数都在[1,n]范围且数值各不相同。 我们想要求,长度为m+1(0<=m<10)的LIS的数量是多少个。 【类型】 DP 树状数组优化 【分析】 这道题很好找到突破口,就是m很小。 于是,我们可以设想一个DP。 用f[i][j]表示最后一个数的位置为i,长度为j的LIS数。 初始化f[1~n][1]=1,答案是∑f[1~n][m]。 具体的转移方程则是——f[i][j]=∑f[p][j-1],p<i且a[p]<a[i]。 然而这个DP方程却是O(n*n*m)的。 于是,我们要采取优化策略。我们需要找到在它之间比它小的数。 在它之间,可以通过扫描顺序解决。 而比它小,则可以通过树状数组动态更新和解决。 【时间复杂度&&优化】 O(nmlog(n)) */