首先显然是是以严格递增子序列的长度为阶段,由于要单调递增,所以还要记录最后一位的数值
$F[i][j]$表示前$i$个数中以$A_i$结尾的长度为j单调递增序列有多少个
$F[i][j]=sum_{k<i且A_k<A_i}^{ }F[k][j-1]$
注意到,如果没有$A_k<A_i$这个条件我们就可以直接维护前缀和了
有$A_k<A_i$这个条件,可以考虑维护$A_i$为下标,$F[i][j-1]$为值的数组的前缀和
$A_i$的值会过大而不能作为下标,要离散化
但是$i$每增加$1$,这个数组并不像之前那样简单的在数组后面加一个值,而是在不确定的地方修改,这样的话如果再是朴素地维护前缀和也起不到上面优化的作用了
待修改的区间求和问题$???$树状数组$!!!$
也就是说维护一个以$A_i$的离散值为下标,$F[i][j-1]$为值的树状数组就好啦
然后讲下细节(敖丙说了细节决定成败$qwq$).就是初始化是$f[0][0]=1$,但是众所周知树状数组的下标不可以为$0$,所以把整个树状数组往右移一位.
$Code$
1 #include<bits/stdc++.h> 2 #define il inline 3 #define Rg register 4 #define go(i,a,b) for(Rg int i=a;i<=b;i++) 5 #define yes(i,a,b) for(Rg int i=a;i>=b;i--) 6 #define mem(a,b) memset(a,b,sizeof(a)); 7 #define int long long 8 using namespace std; 9 il int read() 10 { 11 int x=0,y=1;char c=getchar(); 12 while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();} 13 while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();} 14 return x*y; 15 } 16 const int N=1010,mod=(1e9)+7; 17 int T,n,n1,m,as,a[N],b[N],v[N],c[N],f[N][N]; 18 il int Find(int x){return find(b+1,b+n1+1,x)-b;}//find(b+1,b+n1+1,x)-b;} 19 il int lowbit(int x){return x&(-x);} 20 il void add(int p,int w){while(p<=n1){c[p]=(c[p]+w)%mod;p+=lowbit(p);}} 21 il int sum(int p){int ret=0;while(p){ret=(ret+c[p])%mod;p-=lowbit(p);}return ret%mod;} 22 main() 23 { 24 T=read(); 25 go(TT,1,T)//remember to init 26 { 27 n=read(),m=read(); 28 go(i,1,n)a[i]=b[i]=read(); 29 sort(b+1,b+n+1); 30 n1=unique(b+1,b+n+1)-(b+1); 31 go(i,1,n){v[i]=Find(a[i]);} 32 f[0][0]=1; 33 go(i,1,m) 34 { 35 mem(c,0);if(i==1)add(1,1); 36 go(j,1,n)f[i][j]=sum(v[j]),add(v[j]+1,f[i-1][j]); 37 } 38 as=0;go(i,1,n)as=(as+f[m][i])%mod; 39 printf("Case #%lld: %lld ",TT,as); 40 } 41 return 0; 42 }