大体题意:
给你n 个座位,和m 个人, 安排在一个圆桌子上,要求任意两个人之间的座位至少为k 个,求方案数,答案对1e9取模?
思路:
我们先给m 个人放好,然后在每个人后在添加k 个座位,先保证至少k 个座位,然后会剩下 n - m - m*k个座位,在把剩下的座位插到已经存在的座位里。
那么这个问题就可以转换为:
你有n-m-m*k个球,要求放在m个不同的箱子里,有几种放法?
如果有n 个球,放在m 个不同箱子里。
可以这么考虑,在n 个球后 插入m-1个球,然后任意挑选m-1个球作为隔板,那么答案就是C(n+m-1,m-1)
那么这个题的答案就是 C(n-m-m*k+m-1,m-1) *n/m
之所以乘以n 是因为第一个学生有n 种选择,任意挑选一个座位,但是这样的话难免重复,因为1 3 5 和 3 5 1 和 5 1 3 是一样的,在除以m 就是学生重复的!
然后就是组合数递推取模了, 会有除法,直接快速幂逆元即可!
注意:
只有一个学生,这个公式是不成立的,需要单独判断!
m = 1, ans=n;
在一点是 递推组合数时,不能直接从1递推到n,这样会超时,应该从1 算到 m-1。
详细见代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 1000000 + 10;
ll c[maxn];
ll my_pow(ll a,ll n){
ll ans = 1;
while(n){
if (n & 1)
ans = (ans % mod * a % mod) % mod;
n/=2;
a = (a%mod*a%mod)%mod;
}
return ans;
}
ll C(ll n,ll m){
c[0] = 1;
for (int i = 1; i <= m; ++i)c[i] = (((c[i-1]%mod * (n-i+1)%(mod)) ) * my_pow(i,mod-2)) % mod;
}
ll n, m, k;
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%I64d%I64d%I64d",&n, &m, &k);
if (m == 1){
printf("%d\n",n);
continue;
}
if (n < m + m*k){
printf("0\n");
continue;
}
C(n-m*k-1,m-1);
ll ans = (((n%(mod) * c[m-1] % (mod))%(mod))*my_pow(m,mod-2)) % mod;
printf("%I64d\n",ans);
}
return 0;
}
Description
hannnnah_j is a teacher in WL High school who teaches biology.
One day, she wants to test m students, thus she arranges n different seats around a round table. In order to prevent cheating, she thinks that there should be at least k empty seats between every two students. hannnnah_j is poor at math, and she wants to know the sum of the solutions.So she turns to you for help.Can you help her? The answer maybe large, and you need to mod 1e9+7. Input
First line is an integer T(T≤1000).
The next T lines were given n, m, k, respectively. 0 < m < n < 1e6, 0 < k < 1000 Output
For each test case the output is only one integer number ans in a line.
Sample Input 2 4 2 6 5 2 1 Sample Output 0 5 Source |
Problem descriptions:
|