CF626F Group Projects

分组方案计数显然 dp。

分组与顺序无关,看到最大最小值 dp 不好处理,考虑先将 \(a\) 排序,这样每次加入一个数,若新开一组则对不和谐度之和贡献为 \(-a_i\),若作为一组的最后一元素则贡献 \(a_i\),于是可以设计状态 \(f_{i,j,k}\) 表示前 \(i\) 个数,有 \(j\) 个组还可以往里增加元素,所有组的不和谐度之和为 \(k\) 的方案数,答案为 \(\sum_{p\le k}f_{n,0,p}\)

转移:

\[f_{i,j,k}=f_{i-1,j,k}\cdot(j+1)+f_{i-1,j-1,k+a_i}+f_{i-1,j+1,k-a_i}\cdot (j+1) \]

其中第一项系数还带了 \(i\) 单独一组的情况。

滚一下优化空间,但是第三维大小到了 \(10^5\),因为过程中可以到 \(-s\),其中 \(s=\sum a\)

燃尽了,查看题解后发现将最大值减最小值的贡献转为差分数组一段区间的和,然后每次由 \(i\) 变为 \(i+1\) 对不和谐度之和贡献 \((a_{i+1}-a_i)\cdot j\),这样只用考虑不和谐度之和为正的情况 \(\le k\),有点牛。😱

\(p=a_i-a_{i-1}\) 转移变为:

\[f_{i,j,k}=f_{i-1,j,k-pj}\cdot(j+1)+f_{i-1,j-1,k-p(j-1)}+f_{i-1,j+1,k-p(j+1)}\cdot (j+1) \]

Takanashi Rikka
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define fin(x) freopen(x,"r",stdin)
#define fout(x) freopen(x,"w",stdout)
const int N=205,M=1005,mod=1e9+7;
int a[N],f[2][N][M];
signed main(){
    int n,K;ll ans=0,sum=0,s=0;cin>>n>>K;
    for(int i=1;i<=n;i++)cin>>a[i],sum+=a[i];
    sort(a+1,a+1+n);f[0][0][0]=1;
    for(int i=1;i<=n;i++){s+=a[i];bool p=i&1;
        for(int j=0;j<=i;j++)
            for(int k=0;k<=K;k++){int x=k,P=a[i]-a[i-1];
                f[p][j][x]=((x-P*j>=0?1ll*f[p^1][j][x-P*j]*(j+1)%mod:0)+(j&&x-P*(j-1)>=0?f[p^1][j-1][x-P*(j-1)]:0)+
                           (x-P*(j+1)>=0?1ll*f[p^1][j+1][x-P*(j+1)]*(j+1)%mod:0))%mod;
            }
    }
    for(int p=0;p<=K;p++)(ans+=f[n&1][0][p])%=mod;
    cout<<ans;
    return 0;
}
posted @ 2026-01-13 15:24  Uesugi1  阅读(1)  评论(0)    收藏  举报