[关闭]
@ysner 2018-07-16T21:22:47.000000Z 字数 1894 阅读 2147

分组

DP


题面

有一含个数的数列,询问各组内极差()之和小于等于的分组方案数。

解析

算法

每加入一个数,只有两种方案:新建组加入已有组
以此暴力枚举每一种方案。

算法

预处理个相同数字分为组的方案数
方程为


枚举极差不为的组,其它只能同类数字为一组,统计即可。
实现起来似乎有难度。

算法

枚举两种数的分组情况,再枚举包含两种数的组数(通过将两方各一组合并来实现),用组合数计算。

算法

看到方案数就想想怎么
一开始想设表示前小数,分组后形成极差和为的方案数。
但这样很不好转移,加入一个数后,如果该数单独成组,则不影响极差;如果进入已有组,则影响极差。
再因,如点进入已有组,统计方案数需要当前未关闭组数,我们需要加一维状态:当前未关闭组数。
则设

一个数字有种转移:单独作为一组、新建一个还需填数的组 (代价和 、填入一个已有的组 (不作为最大值)、填入一个已有的组并作为最大值(不再需要填数,代价和)。
如此,则极差和正可达,负可达
复杂度

算法

复杂度瓶颈是
没感到极差和为负是一个很怪异且不太好表示的事情吗?
从另一个角度想,每当我们加入一个数,现存所有未关闭组(个)的极差都将加上,极差和增加
极差和超过就可以停止了。
复杂度降到
而且空间开不下,我们需要滚动(最大特点就是当前数组传完值后要清)。。。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define re register
  8. #define il inline
  9. #define ll long long
  10. #define max(a,b) ((a)>(b)?(a):(b))
  11. #define min(a,b) ((a)<(b)?(a):(b))
  12. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  13. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  14. using namespace std;
  15. const int N=250,mod=1e9+7;
  16. int n,k,a[N],id[N],mn[N],mx[N],tong[N<<2],mxx;
  17. ll ans,dp[2][N][2500],lim;
  18. il ll gi()
  19. {
  20. re ll x=0,t=1;
  21. re char ch=getchar();
  22. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  23. if(ch=='-') t=-1,ch=getchar();
  24. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  25. return x*t;
  26. }
  27. il void ok(re ll &x){while(x>=mod) x-=mod;}
  28. int main()
  29. {
  30. n=gi();lim=gi();
  31. fp(i,1,n) a[i]=gi(),mxx=max(mxx,a[i]);
  32. sort(a+1,a+1+n);
  33. re int now=0,nxt=1;
  34. dp[now][1][0]=dp[now][0][0]=1;
  35. fp(i,1,n-1)
  36. {
  37. fp(j,0,n)
  38. fp(k,0,lim)
  39. {
  40. re ll t=dp[now][j][k],w=k+(a[i+1]-a[i])*j,p=t*j;
  41. ok(p);dp[now][j][k]=0;
  42. if(w>lim) continue;ok(w);
  43. ok(dp[nxt][j][w]+=t);
  44. if(j) ok(dp[nxt][j-1][w]+=p);
  45. ok(dp[nxt][j+1][w]+=t);
  46. ok(dp[nxt][j][w]+=p);
  47. }
  48. swap(now,nxt);
  49. }
  50. fp(i,0,lim) ok(ans+=dp[now][0][i]);
  51. printf("%lld\n",ans);
  52. fclose(stdin);
  53. fclose(stdout);
  54. return 0;
  55. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注