CF1437F
CF1437F
没有什么计数含量,就是暴力dp
按照题目意思走,记录前缀最大值k。离散化即可记录。然后记录当前位置为i
那么
- \(a_i \le \frac{M}{2}\),可以直接加入,方案数就是它的数量
- \(\frac{M}{2} < a_i < M\),不可以加入
- \(k \ge 2M\),加入改变最大值,
那么容易写出dp式子,记录\(dp_{i,j}\)表示前i个中最大是j其中j是离散化(未去重)。那么分类转移,记在 \(i\) 加入的鱼是 \(b_i\)。
- \((x-(i-2))dp_{i-1,j}\)->\(dp_{i,j}\),因为要排除自己所以要-1,其中x是\(\sum_{i=1}^N[2a_i \le a_j]\),至于为什么前面的都一定小等于\(a_j\).
证明:
$\forall k \in [1,i-1] $$, 那么
1.\(k<j\),显然\(2b_k \le b_j\)舍去
2.\(j<k\),\(b_k \ge 2b_j\)或\(b_k \le \frac{b_j}{2}\),但是如果是第一种,最大值就是\(b_k\)舍去。
因此\(\forall k \in [1,i-1] ,b_k \le \frac{b_j}{2}\) - \(dp_{i-1,k}->dp_{i,j},b_k \le \frac{b_j}{2}\)
第二个式子用前缀优化一下即可,第一个式子注意系数小于0时要判掉。
code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define P pair<ll,ll>
void rd(ll& x){
char ch=getchar();
ll f=1;x=0;
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-48;
ch=getchar();
}
x=x*f;
}
const ll N_ = 5005,mod=998244353;
ll N,a[N_],dp[N_][N_],sum[N_][N_],ans;
inline ll ask(ll x)
{
ll l=0,r=N;
while(l<r)
{
ll mid=l+r+1>>1;
if(a[mid]*2<=x)l=mid;
else r=mid-1;
}
return l;
}
int main()
{
rd(N);
for(int i=1;i<=N;i++)rd(a[i]);
sort(a+1,a+1+N);
for(int i=1;i<=N;i++)dp[1][i]++;
for(int i=1;i<=N;i++)sum[1][i]+=sum[1][i-1]+dp[1][i];
for(int i=2;i<=N;i++)
{
for(int j=1;j<=N;j++)
{
ll x=ask(a[j]);
if(x-i+2>=0)dp[i][j]=(dp[i-1][j]*(x-i+2)%mod+dp[i][j])%mod;
dp[i][j]=(dp[i][j]+sum[i-1][x])%mod;
sum[i][j]=(dp[i][j]+sum[i][j-1])%mod;
}
}
for(int i=1;i<=N;i++)ans=(ans+dp[N][i])%mod;
cout<<ans;
return 0;
}

浙公网安备 33010602011771号