$dp$。
一开始想了一个$dp$做法,$dp[i][j]$表示前$i$个数字,下降序列长度为$j$的方案数为$dp[i][j]$,这样做需要先离散化然后用树状数组优化,空间复杂度为${n^2}$,时间复杂度为$O({n^2}log n)$,这样的做法被$POJ$卡了内存。既然是$MLE$,然后我去$discuss$测了一下数据,发现答案都是对的。
$MLE$:
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<iostream> using namespace std; typedef long long LL; const double pi=acos(-1.0),eps=1e-8; void File() { freopen("D:\in.txt","r",stdin); freopen("D:\out.txt","w",stdout); } const int maxn=5010; int f[maxn][maxn],h[maxn][maxn],n,a[maxn],b[maxn]; int c[maxn][maxn]; int pre[(1<<16)+20]; int get(int x) { int L=1,R=n,res; while(L<=R) { int mid=(L+R)/2; if(b[mid]<x) L=mid+1; else if(b[mid]==x) res=mid,L=mid+1; else R=mid-1; } return res; } int lowbit(int x){return x&(-x);} int sum(int p,int x) { int res=0; for(int i=x;i>0;i=i-lowbit(i)) res=res+c[p][i]; return res; } void update(int p,int x,int val) { for(int i=x;i<=5001;i=i+lowbit(i)) c[p][i]=c[p][i]+val; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+1+n); for(int i=1;i<=n;i++) a[i]=get(a[i]); memset(h,0,sizeof h); memset(c,0,sizeof c); memset(f,0,sizeof f); memset(pre,0,sizeof pre); h[0][0]=1; f[0][0]=1; update(0,5001,1); for(int i=1;i<=n;i++) { for(int j=1;j<=i;j++) h[i][j]=sum(j-1,5001)-sum(j-1,a[i]); int p=pre[a[i]]; for(int j=1;j<=n;j++) f[i][j]=h[i][j]-h[p][j]; for(int j=1;j<=n;j++) update(j,a[i],f[i][j]); pre[a[i]]=i; } for(int j=n;j>=1;j--) { int ans=0; for(int i=1;i<=n;i++) ans=ans+f[i][j]; if(ans==0) continue; else { printf("%d %d ",j,ans); break; } } return 0; }
事实上,上述做法中很多信息都是冗余的,我们只需记录到$i$位置的最长下降序列的长度$f[i]$以及方案数$g[i]$就可以了。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<iostream> using namespace std; typedef long long LL; const double pi=acos(-1.0),eps=1e-8; void File() { freopen("D:\in.txt","r",stdin); freopen("D:\out.txt","w",stdout); } const int maxn=5010; int n,a[maxn],f[maxn],g[maxn]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) { f[i]=1; g[i]=1; bool flag=0; for(int j=i-1;j>=1;j--) { if(a[j]<a[i]) continue; if(a[j]==a[i]) { if(flag==0) g[i]=0; break; } else if(a[j]>a[i]) { flag=1; if(f[j]+1>f[i]) f[i]=f[j]+1,g[i]=g[j]; else if(f[j]+1==f[i]) g[i]=g[i]+g[j]; } } } int ans=0; for(int i=1;i<=n;i++) ans=max(ans,f[i]); int ans2=0; for(int i=1;i<=n;i++) if(f[i]==ans) ans2=ans2+g[i]; printf("%d %d ",ans,ans2); return 0; }