Loading

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;
}
posted @ 2026-09-09 20:56  leaf_ydc  阅读(8)  评论(0)    收藏  举报