【GDOI2017模拟10.30】分组
2016-10-31 16:54
225 查看
题目大意
给定n个数和一个k,要给这n个数分成若干组,满足∑每组元素的极差不大于k。求方案数模109+7的值。数据范围
n≤200 k≤1000 si≤500分析
对于一个组,我们只关心它的最大、最小值。可以先给n个数降序排序,设f[i][j][k]表示前i大的数,现在有j组还没确定最小值(此时最小值视为0),极差和为k,列出DP方程:f[i][j][k]=f[i−1][j][k](表示第i个数单独一组)+f[i−1][j][k]∗j(第i个数放在其中一组,不是最小值)+f[i−1][j−1][k−s[i]](新开一组)+f[i−1][j+1][k+s[i]]∗(j+1)(第i个数作为最小值放在其中一组)
作差思想
第三维状态显然很大,需要优化。令c[i]=s[i]-s[i-1],那么一个组原本的极差为s[i]-s[j],现在变成了∑c[i]
再看看转移:
f[i][j][k]=f[i−1][j][k−c[i]∗j]+f[i−1][j][k−c[i]∗j]∗j+f[i−1][j−1][k−c[i]∗j]+f[i−1][j+1][k−c[i]∗j]∗(j+1)
这样就可以把第三维设成0——k的了。
为了省空间要打滚动数组。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=205,M=1005,mo=1e9+7; typedef long long LL; int n,m,s ,f[2] [M],p,q,a ,ans; bool cmp(int x,int y) { return x>y; } int main() { freopen("group.in","r",stdin); freopen("group.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&s[i]); sort(s+1,s+n+1,cmp); for (int i=2;i<=n;i++) a[i]=s[i-1]-s[i]; a[1]=0; p=0; q=1; f[0][0][0]=1; for (int i=1;i<=n;i++,p^=1,q^=1) { memset(f[q],0,sizeof(f[q])); for (int j=0;j<i;j++) { for (int k=a[i]*j;k<=m;k++) { f[q][j][k]=(f[q][j][k]+(LL)f[p][j][k-a[i]*j]*(j+1))%mo; f[q][j+1][k]=(f[q][j+1][k]+f[p][j][k-a[i]*j])%mo; if (j>0) f[q][j-1][k]=(f[q][j-1][k]+(LL)f[p][j][k-a[i]*j]*j)%mo; } } } ans=0; for (int i=0;i<=m;i++) ans=(ans+f[p][0][i])%mo; printf("%d\n",ans); fclose(stdin); fclose(stdout); return 0; }
相关文章推荐
- GDOI2017模拟10.30 总结
- 【GDOI2017模拟11.4】Walk
- Silverlight实用窍门系列:73.Silverlight的DataGrid分组以及模拟合并单元格
- 【GDOI2017第二轮模拟day1】公路建设(克鲁斯卡尔最小生成树+线段树+归并)
- GDOI2017模拟04.15总结
- 【GDOI2017第四轮模拟day2】叶片
- 模拟多级表头的分组统计
- JZOJ4857. 【GDOI2017模拟11.4】Tourist Attractions
- JZOJ 4863 【GDOI2017模拟11.5】Market
- 【GDOI2017模拟一试4.11】腐女的生日(线段树+维护一次函数)
- 【GDOI2017模拟8.15】Buy
- 模拟多级表头的分组统计
- 【GDOI2017第四轮模拟day2】绝版题
- 模拟多级表头的分组统计
- 【faebdc的模拟赛】T2分组
- 【GDOI2017模拟2.25】神秘物质
- 【GDOI2017模拟11.3】永恒的契约
- 【GDOI2017模拟11.2】相位幻击
- JZOJ4843. 【GDOI2017模拟11.2】相位幻击
- 【jzoj5322】【GDOI2017模拟8.21】【小朋友】【状态压缩动态规划】