1. 程式人生 > 實用技巧 >題解 CF1188C 【Array Beauty】

題解 CF1188C 【Array Beauty】

考慮對美麗值進行 \(DP\) 來統計答案,發現直接統計美麗值等於 \(v\) 的子序列方案數不好統計,不妨統計美麗值大於等於 \(v\) 的方案數。發現這樣統計,美麗值為 \(v\) 的一個子序列在區間 \([1,v]\) 都會有貢獻,所以這樣的合法子序列的方案數即為答案。

先對 \(a\) 進行排序,由抽屜原理得美麗值的最大值為 \(\frac{a_n}{k-1}\)。列舉當前考慮的美麗值為 \(v\),設 \(f_{i,j}\) 為考慮了前 \(i\) 個數,選了 \(j\) 個數的合法子序列方案數,得:

\[f_{i,j} = f_{i-1,j} + f_{pos,j-1} \]

其中 \(pos\)

為最後一個滿足 \(a_i - a_{pos} \geqslant v\) 的位置,轉移時只用考慮 \(pos\) 的貢獻,因為之前的合法位置的貢獻已經統計到 \(pos\) 了。因為滿足單調性,所以求 \(pos\) 用雙指標即可。

#include<bits/stdc++.h>
#define maxn 1010
#define p 998244353
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,k,ans;
int a[maxn],f[maxn][maxn];
int calc(int v)
{
    int pos=0;
    for(int i=1;i<=n;++i)
    {
        f[i][0]=1;
        while(a[i]-a[pos+1]>=v) pos++;
        for(int j=1;j<=k;++j)
            f[i][j]=(f[i-1][j]+f[pos][j-1])%p;
    }
    return f[n][k];
}
int main()
{
    read(n),read(k),f[0][0]=1;
    for(int i=1;i<=n;++i) read(a[i]);
    sort(a+1,a+n+1);
    for(int i=1;i<=a[n]/(k-1);++i) ans=(ans+calc(i))%p;
    printf("%d",ans);
    return 0;
}