1 条题解

  • 0
    @ 2026-5-6 15:15:07

    第一眼看到这题,想打暴力,但是发现并不好打,我们对于暴力有一个贪心策略:

    • 如果前 FF 个数小于 TT,那么我们肯定是想办法移出去一个小的,换回来个大的。

    可是我们发现知道了也没用,因为你知道这个直接暴力去做时间复杂度肯定极高,但是我们不用真的模拟题意给它移出去,我们考虑用 DP 来写这个题。

    我们设 dpi,jdp_{i,j} 为前 ii 个数选 jj 个和最大,于是你会发现这样并不好记录答案只是求出有没有解,那么这个时候我们引入一句话:

    DP 不好写,那就再加一维。

    好了现在我们考虑三维 DP,设 dpi,j,kdp_{i,j,k} 为前 ii,个数选 jj 个,用 kk 步,且和最大,现在我们可以枚举 i,j,ki,j,k,时间复杂度 Θ(n3F)\Theta(n^3F),不需要优化,可以通过。

    状态转移方程也很简单,我们考虑 ii 这个位置选还是不选:

    • 如果 ii 选,那么你要把 aia_i 移到 [1,j][1,j] 这个区间也就是要 (ij)(i-j) 步,所以 dpi,j,k=dpi1,j1,ki+j+aidp_{i,j,k}=dp_{i-1,j-1,k-i+j}+a_i
    • 否则直接转移过来就行 dpi,j,k=dpi1,j,kdp_{i,j,k}=dp_{i-1,j,k}

    最终答案就是对与选前 nn 个数选 FF,答案大于等于 TT,最小的 kk

    注意:kk 最多枚举到 i×(i1)2\frac{i \times (i-1)}{2},所以 dpdp 的第三维要开到 n×(n1)2\frac{n \times (n-1)}{2} 这个其实就是完全逆序时逆序对的对数至于为什么是这个,建议读者自行推导。

    :::success[Ac Code]

    #include <bits/stdc++.h>
    using namespace std;
    #ifdef __linux__
    #define gc getchar_unlocked
    #define pc putchar_unlocked
    #else
    #define gc _getchar_nolock
    #define pc _putchar_nolock
    #endif
    #define int long long
    #define _ read<int>()
    #define rint register int
    #define R register
    inline bool blank(const char &x)
    {
        return !(x^10)||!(x^9)||!(x^13)||!(x^32);
    }
    template<class T>inline T read()
    {
        T r=0,f=1;R char c=gc();
        while(!isdigit(c))
        {
            if(c=='-') f=-1;
            c=gc();
        }
        while(isdigit(c)) r=(r<<1)+(r<<3)+(c^48),c=gc();
        return f*r;
    }
    inline void out(rint x)
    {
        if(x<0) pc('-'),x=-x;
        if(x<10) pc(x+'0');
        else out(x/10),pc(x%10+'0');
    }
    inline void read(char &x)
    {
        for(x=gc();blank(x)&&(x^-1);x=gc());
    }
    const int N=110,INF=1145141919810;
    int dp[N][N][(N*N)>>1],a[N];
    signed main()
    {
        rint n=_,F=_,T=_;
        for(rint i=1;i<=n;i++) a[i]=_;
        for(rint i=1;i<=n;i++)
        {
            for(rint j=1;j<=min(i,F);j++)
            {
                for(rint k=0;k<=(((i-1)*i)>>1);k++)
                {
                    dp[i][j][k]=dp[i-1][j][k];
                    if(k+j>=i) dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][k-i+j]+a[i]);
                }
            }
        }
        rint ans=INF;
        for(rint k=0;k<=(n*(n-1)>>1);k++)
        {
            if(dp[n][F][k]>=T) ans=min(ans,k);
        }
        if(ans==INF) puts("NO");//凑不出
        else out(ans);
        return 0;
    }
    

    :::

    • 1

    信息

    ID
    10939
    时间
    1000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者