题目

  点这里看题目。

分析

  可以想到用 DP 解决。

  由于把空位放到状态里面太麻烦了,因此我们单独将 " 组 " 提出来进行 DP 。

  \(f(i,j)\):前\(i\)个人组成\(j\)个组的方案数。

  此时这个组是有顺序有编号的,并且按照编号相邻(由于在环上,\(j\) 组和 \(1\) 组也算相邻)。

  考虑三种转移:

  1.我们新建一组,并在原来的一个组后面插入新组:\(f(i+1,j+1)+=j*f(i,j)\);

  2.我们将新的人安排到新的组里面,可以放在组的两头:\(f(i+1,j)+=2j*f(i,j)\);

  3.我们用一个人将两个组合在一起,有\(j\)个组相邻:\(f(i+1,j-1)+=j*f(i,j)\);

  可以发现这样 DP 只需要保证中途状态不会超过\(G\)组即可。

  环上问题,我们可以先固定第一个人的位置,计算出方案数然后再乘上\(n\)。因此\(f(1,1)=1\)。

  现在考虑怎么再组与组之间插入空位组成结果。设现在分配\(g\)个组,第\(i\)个组后有\(x_i\)个空位,则可以得到:

\[\sum_{i=1}^g x_i=n-k\ |x_i\ge 1
\]

  这是一个可用插板法解决的问题,因此可以快速计算方案数。

  因此一般情况的答案为:

\[\sum_{i=1}^G f(k,i)\times C_{n-k-1}^{i-1}
\]

  但是如果\(n=k\),则组合数下标为\(-1\),不能算。这实际上是位置会被坐满,只有一个组的情况。当第\(k\)个人入座的时候,他只可能有一个位置可坐,因此方案数为\(n\times f(k-1,1)\)。

代码

#include <cstdio>

const int mod = 1e9 + 7;
const int MAXN = 2005; template<typename _T>
void read( _T &x )
{
x = 0;char s = getchar();int f = 1;
while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
x *= f;
} template<typename _T>
void write( _T x )
{
if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
if( 9 < x ){ write( x / 10 ); }
putchar( x % 10 + '0' );
} int f[MAXN][MAXN], C[MAXN][MAXN];
int N, K, G; void upt( int &x, const int v ) { x = ( x + v ) % mod; } void init()
{
C[0][0] = 1;
for( int i = 1 ; i <= N ; i ++ )
{
C[i][0] = C[i][i] = 1;
for( int j = 1 ; j < i ; j ++ ) C[i][j] = ( C[i - 1][j] + C[i - 1][j - 1] ) % mod;
}
} class Seatfriends
{
public:
int countseatnumb( const int n, const int k, const int g )
{
N = n, K = k, G = g;
init();
f[1][1] = 1;
for( int i = 1 ; i < K ; i ++ )
for( int j = 1 ; j <= G ; j ++ )
{
upt( f[i + 1][j], 2ll * j * f[i][j] % mod );
upt( f[i + 1][j + 1], 1ll * j * f[i][j] % mod );
if( j > 1 ) upt( f[i + 1][j - 1], 1ll * j * f[i][j] % mod );
}
int ans = 0;
if( N == K ) return 1ll * f[K - 1][1] * N % mod;
for( int i = 1 ; i <= G ; i ++ )
upt( ans, 1ll * f[K][i] * ( N == K ? 1 : C[N - K - 1][i - 1] ) % mod );
return 1ll * ans * N % mod;
}
};

最新文章

  1. 使用Design包实现QQ动画侧滑效果和滑动菜单导航
  2. Java并发_volatile实现可见性但不保证原子性
  3. PHP数组的常用函数
  4. ajax状态
  5. ExtJS学习之路第二步:Ext.Component 和 Ext.dom.Element 的区别
  6. Maven学习记录
  7. Kafka 快速起步(作者:杜亦舒)
  8. XML Schema使用技巧——unique
  9. java 面向对象 1
  10. iOS如何提高页面流畅度
  11. Android中Activity被系统会收前页面信息保存
  12. 学习Python3基础知识过程中总结
  13. 【Codeforces 464D】World of Darkraft - 2
  14. R和python语言如何求平均值,中位数和众数
  15. Best Paper Awards in Computer Science 链接
  16. SQL语句报错,无法绑定由多个部分组成的标识符解决
  17. linux下查看内存使用情况
  18. redis数据持久化(快照/日志):
  19. Falsy Bouncer
  20. .netCore2.0 程序集DI依赖注入

热门文章

  1. LightOJ1236
  2. 【学习】Python os模块常用方法 记录
  3. python+selenium 自动化测试框架-学习记录
  4. 关闭 WordPress 自动更新
  5. PHP基础-自定义函数-变量范围-函数参数传递
  6. 【Elasticsearch学习】DSL搜索大全(持续更新中)
  7. Django创建应用以及路由的配置
  8. 重磅!阿里P8费心整理Netty实战+指南+项目白皮书PDF,总计1.08G
  9. 【JavaScript数据结构系列】03-队列Queue
  10. eatwhatApp开发实战(二)