CF626F Group Projects
有n个学生,每个学生有一个能力值ai。现在要把这些学生分成一些(任意数量的)组,每一组的“不和谐度”是该组能力值最大的学生与能力值最小的学生的能力值的差。求所有不和谐度之和不超过k的分组方案总数。
输入输出样例
输入 #1
3 2
2 4 5
输出 #1
3
输入 #2
4 3
7 8 9 10
输出 #2
13
输入 #3
4 0
5 10 20 21
输出 #3
View Code
1
hint:n<=200,k<=1000
sol:
把a排序
注意到不和谐度一定是一个终点的值-起点的值,中间可能还有几个非终非起的点,随便放即可
dp[i,j,k]表示前i个数,还有j个起点未匹配,当前总贡献为k个方案数
转移就是枚举当前点做起点,中间点,终点
然后就会挂的很惨,有一种很坑的东西,就是一个点既是起点又是终点
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* 把a排序 注意到不和谐度一定是一个终点的值-起点的值,中间可能还有几个非终非起的点,随便放即可 dp[i,j,k]表示前i个数,还有j个起点未匹配,当前总贡献为k个方案数 转移就是枚举当前点做起点,中间点,终点 然后就会挂的很惨,有一种很坑的东西,就是一个点既是起点又是终点 */ #include <bits/stdc++.h> using namespace std; typedef int ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) {f|=(ch=='-'); ch=getchar();} while(isdigit(ch)) {s=(s<<3)+(s<<1)+(ch^48); ch=getchar();} return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) {putchar('-'); x=-x;} if(x<10) {putchar(x+'0'); return;} write(x/10); putchar((x%10)+'0'); } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') const int Mod=1000000007,N=205; int n,m,a[N]; int dp[2][N][1005]; inline void Ad(int &x,int y) { x+=y; x-=(x>=Mod)?Mod:0; } int main() { freopen("codeforces626F_data.in","r",stdin); int i,j,k,t; R(n); R(m); for(i=1;i<=n;i++) R(a[i]); sort(a+1,a+n+1); dp[t=0][0][0]=1; for(i=1;i<=n;i++) { t^=1; for(j=0;j<=min(i,n>>1);j++) { int oo=a[i]-a[i-1]; for(k=0;k<=m;k++) { dp[t][j][k]=0; if(j&&k>=(j-1)*oo) Ad(dp[t][j][k],dp[t^1][j-1][k-(j-1)*oo]); if(k>=j*oo) Ad(dp[t][j][k],1LL*dp[t^1][j][k-j*oo]*j%Mod); if(k>=(j+1)*oo) Ad(dp[t][j][k],1LL*dp[t^1][j+1][k-(j+1)*oo]*(j+1)%Mod); if(k>=j*oo) Ad(dp[t][j][k],dp[t^1][j][k-j*oo]); } } } int ans=0; for(i=0;i<=m;i++) Ad(ans,dp[t][0][i]); Wl(ans); return 0; }