1 条题解
-
0
考虑先找出一个子序列,满足每个数都大于等于前一个数的两倍,然后再去放其他数。
先排序,我们从后向前放。
设 表示放到 的答案是什么。
可以枚举一个 使 ,然后考虑放 区间中的数。
考虑现在取出的子序列是 ,那么 区间中的数有些可以放到 的后面,有些只能放在 的后面。
考虑分成两类,记 表示最后面的一个小于 的位置。
分类,然后放就好了,细节比较多,讨论一下。
代码
#include<bits/stdc++.h> using namespace std; const int N=5005,mod=998244353; int n,a[N],f[N],dp[N],inv[N],g[N]; int kuai(int a,int b){ int ans=1; for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod; return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); sort(a+1,a+n+1); if(a[n-1]*2>a[n]) { puts("0"); return 0; } dp[n]=1; for(int i=1;i<=n;i++){ for(int j=1;j<i;j++){ if(a[j]*2<=a[i])g[i]=j; } } f[1]=f[0]=1; for(int i=2;i<=n;i++)f[i]=1ll*f[i-1]*i%mod;//阶乘 for(int i=0;i<=n;i++)inv[i]=kuai(f[i],mod-2); for(int i=n-1;i>=0;i--){ for(int j=i+1;j<=n;j++){ if(a[i]*2<=a[j]){ int num=1; if(n-i-1>=n-g[j])num=1ll*num*f[n-i-1]%mod*inv[n-g[j]-1]%mod;//如果存在可以放到j后面的 if(n-2-g[j]>=n-j){//如果只能放在k后面 if(n-j)num=1ll*num*f[n-2-g[j]]%mod*inv[n-j-1]%mod; else num=1ll*num*f[n-2-g[j]]%mod; } dp[i]=(dp[i]+1ll*dp[j]*num%mod)%mod; } } } printf("%d",dp[0]);//答案是dp[0],所有的数都放完了。 return 0; }
- 1
信息
- ID
- 10
- 时间
- 4000ms
- 内存
- 1024MiB
- 难度
- (无)
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者