大体题意:
给你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. Input First line is an integer T(T≤1000). Output For each test case the output is only one integer number ans in a line. Sample Input 24 2 65 2 1 Sample Output 05 Source 2016 ACM/ICPC Asia Regional Shenyang Online | Problem descriptions: Initialization. |
Time Limit: 1000MS | | Memory Limit: 131072KB | | 64bit IO Format: %I64d & %I64u |