我们定义f[i][j]表示前j个数组成的长度为i的合法序列的个数,那么有
因此我们不难写出朴素dp的代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 typedef long long ll; 7 int T,n,m,a[1100],ans; 8 int f[1100][1100]; 9 const int mod=1000000007; 10 inline int read() { 11 int ret=0; 12 int op=1; 13 char c=getchar(); 14 while(c<'0'||c>'9') {if(c=='-') op=-1; c=getchar();} 15 while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar(); 16 return ret*op; 17 } 18 int main() { 19 T=read(); 20 for(int t=1;t<=T;t++) { 21 memset(a,0,sizeof(a)); 22 memset(f,0,sizeof(f)); 23 n=read(); m=read(); 24 for(int i=1;i<=n;i++) a[i]=read(); 25 f[0][0]=1; 26 a[0]=-(1<<30); 27 ans=0; 28 for(int i=1;i<=m;i++) 29 for(int j=1;j<=n;j++) 30 for(int k=0;k<j;k++) 31 if(a[k]<a[j]) f[i][j]=(f[i][j]+f[i-1][k])%mod; 32 for(int i=1;i<=n;i++) ans=(ans+f[m][i])%mod; 33 printf("Case #%d: %d\n",t,ans); 34 } 35 return 0; 36 }TLE Code
然而,这种做法的时间复杂度较大,无法通过本题,因此我们考虑优化。
我们将序列A的值离散化,用num[i]表示i离散化后的值,另外,我们令A0=-∞,num[A0]=1,然后建立树状数组维护即可。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 inline int read() { 7 int ret=0; 8 int op=1; 9 char c=getchar(); 10 while(c<'0'||c>'9') {if(c=='-') op=-1; c=getchar();} 11 while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar(); 12 return ret*op; 13 } 14 int T,n,m,a[1100],b[1100],num[1100]; 15 int f[1100][1100]; 16 int sum[1100]; 17 const int mod=1000000007; 18 #define lowbit(x) ((-x)&(x)) 19 int query(int x) { 20 int ret=0; 21 while(x>0) { 22 ret=(ret+sum[x])%mod; 23 x-=lowbit(x); 24 } 25 return ret; 26 } 27 void add(int x,int val) { 28 while(x<=n) { 29 sum[x]=(sum[x]+val)%mod; 30 x+=lowbit(x); 31 } 32 } 33 int main() { 34 T=read(); 35 for(int t=1;t<=T;t++) { 36 memset(a,0,sizeof(a)); 37 memset(f,0,sizeof(f)); 38 memset(b,0,sizeof(b)); 39 memset(num,0,sizeof(num)); 40 n=read(); m=read(); 41 for(int i=1;i<=n;i++) { 42 a[i]=read(); 43 b[i]=a[i]; 44 } 45 a[0]=b[n+1]=-(1<<30); 46 sort(b+1,b+n+1+1); 47 for(int i=0;i<=n;i++) num[i]=lower_bound(b+1,b+n+1,a[i])-b; 48 f[0][0]=1; 49 for(int i=1;i<=m;i++) { 50 memset(sum,0,sizeof(sum)); 51 add(num[0],f[i-1][0]); 52 for(int j=1;j<=n;j++) { 53 f[i][j]=query(num[j]-1); 54 add(num[j],f[i-1][j]); 55 } 56 } 57 int ans=0; 58 for(int i=1;i<=n;i++) ans=(ans+f[m][i])%mod; 59 printf("Case #%d: %d\n",t,ans); 60 } 61 return 0; 62 }AC Code