1 条题解
-
0
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=505,M=1e3+5,P=1e9+7; int n,m,ans; int s[N]; int f[2][N][M]; //对于i个学生分了j组不和谐度之和为k的方案数为f[i][j][k] //update i个学生目前还有j组可以加入,总不和谐度是k的方案数 void add(int &x,ll y){x=(x+y)%P;} int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d",&s[i]); sort(s+1,s+1+n); f[1][0][0]=f[1][1][0]=1; //初始化 1个人的时候只有一种可能 //f[i][0][k] 已考虑i个人不和谐度为k时所有分组方案之和 //本质是所有组都已经关闭,即分完组 for(int i=2;i<=n;++i) { int now=i&1; memset(f[now],0,sizeof(f[now])); for(int j=0;j<i;++j) { int delta=j*(s[i]-s[i-1]); //用差分的形式保证了不和谐度与当前组内的最小s没有关系 //对于j的解释: //目前有j个组正在开放,所以至少要再进入j个更大的数 //在j个组都封闭后,考虑差分,必然会对k产生j倍贡献 for(int k=0;k+delta<=m;++k) { int sum=k+delta; //判断到达性 if(!f[now^1][j][k]) continue; //保证第i个学生是最慢的 //所以要再开放一个组 add(f[now][j+1][sum],f[now^1][j][k]); //保证第i个学生是某个组里最快的 //所以要封闭一个组 if(j) add(f[now][j-1][sum],1ll*f[now^1][j][k]*j); //保证第i个学生是某个组里的中间 //对于(j+1)的解释 j是可以在j组选择中任选一组 //+1是因为可以先自己新开一组,然后马上自闭 add(f[now][j][sum],1ll*f[now^1][j][k]*(j+1)); } } } for(int i=0,now=n&1;i<=m;++i) add(ans,f[now][0][i]); printf("%d",ans); return 0; }
- 1
信息
- ID
- 459
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 16
- 已通过
- 7
- 上传者