$n leq 200$个数,$ leq 500$,$K leq 1000$代价内的数字分组有多少?一个分组的代价是分成的每个小组的总代价;一个小组的代价是极差。
问的极差那就从极入手嘛。一个小组只有最大和最小值是有用滴!那就来分这些最大最小值。
由于考虑大小,不如先把数列排个序。这样的话,可以表示出那种“有几个小组分不满”的形似插头DP的状态,在移动到下一个数时代价加上当前数和下一个数的差乘上还没分配满的小组数即可。具体,$f(i,j,k)$表示前$i$个数$j$个小组还没满,当前代价$k$的方案,如此不需要知道最小值们是谁,只需在$i$移动到$i+1$时,每个没配满的小组加上$a_{i+1}-a_i$的代价即可,因此没配满小组数$j$就可以计算代价。转移的话,分$i$单独一组、新开一个未满组、加入之前一个未满组、充当之前一个未满组的最大值,来转移。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 //#include<math.h> 5 //#include<queue> 6 //#include<vector> 7 #include<algorithm> 8 //#include<iostream> 9 //#include<assert.h> 10 using namespace std; 11 12 int n,K; 13 const int mod=1e9+7; 14 int a[222],f[2][222][1111],cur; 15 16 int main() 17 { 18 scanf("%d%d",&n,&K); 19 for (int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+1+n); 20 cur=0; f[0][0][0]=1; 21 for (int i=1;i<=n;i++) 22 { 23 for (int j=0;j<=n;j++) 24 for (int k=0,tmp=j*(a[i]-a[i-1]),to=K-tmp;k<=to;k++,tmp++) if (f[cur][j][k]) 25 { 26 f[cur^1][j+1][tmp]+=f[cur][j][k]; f[cur^1][j+1][tmp]-=f[cur^1][j+1][tmp]>=mod?mod:0; 27 f[cur^1][j][tmp]+=(j+1)*1ll*f[cur][j][k]%mod; f[cur^1][j][tmp]-=f[cur^1][j][tmp]>=mod?mod:0; 28 if (j>0) 29 {f[cur^1][j-1][tmp]+=j*1ll*f[cur][j][k]%mod; f[cur^1][j-1][tmp]-=f[cur^1][j-1][tmp]>=mod?mod:0;} 30 } 31 memset(f[cur],0,sizeof(f[cur])); 32 cur^=1; 33 } 34 35 int ans=0; for (int i=0;i<=K;i++) ans+=f[cur][0][i],ans-=ans>=mod?mod:0; 36 printf("%d ",ans); 37 return 0; 38 }