CF1188C Array Beauty(DP)

日常降智。

不过还是第一次和 2700 的题正解这么近呢……


由于排序后不影响答案,而且直觉告诉我们排序后会更好做,不妨排个序。

直觉告诉我们,变成求最小差 \(\ge v\) 的方案数会比最小差 \(=v\) 的方案数好算。

问题就变成如何求最小差 \(\ge v\) 的方案数。

\(f_{i,j}\) 表示前 \(i\) 个数中选了 \(j\) 个,且 \(i\) 被选了的方案数。有 \(f_{i,1}=1\)

转移:\(f_{i,j}=\sum\limits_{a_i-a_k\ge v}f_{k,j-1}\)

很明显可以前缀和+双指针优化。

时间复杂度 \(O(nka_\max)\)。然后我就自闭了。

%了一发 wqy 的题解,太神了吧……

其实是最小差的最大值达不到 \(a_\max-a_\min\),而只有 \(\frac{a_\max-a_\min}{k-1}\)。(抽屉原理)

扫描二维码关注公众号,回复: 7047509 查看本文章

复杂度立刻降到 \(O(nk\frac{a_\max}{k-1})=O(na_\max)\)

看来……会很多的 DP 套路优化,发掘不了性质,还是只能被吊打……

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=1111,mod=998244353;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
    char ch=getchar();ll x=0,f=0;
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,k,a[maxn],f[maxn][maxn],s[maxn][maxn],ans; 
int main(){
    n=read();k=read();
    FOR(i,1,n) a[i]=read();
    sort(a+1,a+n+1);
    FOR(x,1,(a[n]-a[1])/(k-1)){
        FOR(i,0,n) FOR(j,0,k) f[i][j]=s[i][j]=0;
        FOR(i,1,n) f[i][1]=1,s[i][1]=i;
        FOR(j,2,k){
            int cur=0;
            FOR(i,1,n){
                while(cur<i && a[i]-a[cur]>=x) cur++;
                if(cur && a[i]-a[cur]<x) cur--;
                f[i][j]=s[cur][j-1];
                s[i][j]=(s[i-1][j]+f[i][j])%mod;
            }
        }
        ans=(ans+s[n][k])%mod;
    }
    printf("%d\n",ans);
}

猜你喜欢

转载自www.cnblogs.com/1000Suns/p/11368195.html
今日推荐