组合数学-HDU5894
来源:互联网 发布:js json双引号转义 编辑:程序博客网 时间:2024/06/03 18:38
https://vjudge.net/contest/183475#problem/C
题目大意:
圆周上有N个不同的椅子,要让M个相同的人坐在上面,使得两人之间至少隔K把空椅子,求方案数(模1e9+7)。
0< M < N<1e6, 0< K<1000.
题解:
考虑每两个人之间隔了几把椅子。可以发现,一共有M个数,和为N-M,且每个数都>=K.将每个数都减去K-1,即得到:M个正数之和为N-K*M,方案数为C(N-K*M-1,M-1).需要乘以圆排列的N,同时每个方案被算了M次,再除以M。
因为有n个位置,所以第一个人位置的选法就有n种
再考虑此题中每个人都是一样的,即不同方案仅仅是坐的位置序列不同,那上述做法会重复计算m次
比如有3个人,假设他们坐的位置是(2,4,7),那么,(4,2,7),(7,2,4)是重复计算的
答案为:C(N-K*M-1,M-1)*N/M。需要用预处理阶乘的方法计算组合数。注意特判M=1的情况。
#include<bits/stdc++.h>#define ll long longconst ll mod=1e9+7;using namespace std;ll qmod(ll n,ll m,ll mod){ ll ans=1; while(m) { if(m&1)ans=(ans*n)%mod; m>>=1; n=(n*n)%mod; } return ans;}ll C(ll n,ll m){ if(n<m||n<0||m<0) return 0; ll ans=1; for(int i=1;i<=m;i++) ans=(ans*(n-i+1)%mod)*qmod(i,mod-2,mod)%mod; return ans;}int main(){ int t; scanf("%d",&t); while(t--) { int n,m,k; scanf("%d%d%d",&n,&m,&k); if(m==1) { printf("%d\n",n); continue; } ll ans=C(n-m*k-1,m-1); ans=(ans*n%mod)*qmod(m,mod-2,mod)%mod; printf("%I64d\n",ans); }}
对阶乘和阶乘逆元打表,用时更短
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <stack> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> #include <time.h> using namespace std; #define showtime fprintf(stderr,"time = %.15f\n",clock() / (double)CLOCKS_PER_SEC) #define lld %I64d #define REP(i,k,n) for(int i=k;i<n;i++) #define REPP(i,k,n) for(int i=k;i<=n;i++) #define scan(d) scanf("%d",&d) #define scanl(d) scanf("%I64d",&d) #define scann(n,m) scanf("%d%d",&n,&m) #define scannl(n,m) scanf("%I64d%I64d",&n,&m) #define mst(a,k) memset(a,k,sizeof(a)) #define LL long long #define N 1000005 #define mod 1000000007 inline int read(){int s=0;char ch=getchar();for(; ch<'0'||ch>'9'; ch=getchar());for(; ch>='0'&&ch<='9'; ch=getchar())s=s*10+ch-'0';return s;} LL f[N], f2[N], inv[N]; void init() { f[0] = f[1] = f2[0] = f2[1] = inv[0] = inv[1] = 1; for (int i = 2; i < N; i++) { f[i] = f[i - 1] * i % mod; //阶乘打表 inv[i] = inv[mod % i] * (mod - mod / i) % mod; //求逆元 f2[i] = f2[i - 1] * inv[i] % mod; //阶乘逆元打表 } } inline LL C (int n, int m) { if (m < 0 || n < m) return 0; return f[n] * f2[m] % mod * f2[n - m] % mod; } int main() { init(); int t; scan(t); while(t--) { int n,m,k; scann(n,m);scan(k); if(m==1) { printf("%d\n",n); continue; } LL ans = C(n-1-m*k,m-1) * inv[m] % mod * n % mod; printf("%lld\n",ans); } return 0; }
阅读全文
0 0
- hdu5894组合数学
- HDU5894【组合数学】
- 组合数学-HDU5894
- HDU5894-hannnnah_j’s Biological Test【组合数学】
- HDU5894-hannnnah_j’s Biological Test(组合数学+Lucas定理)
- hdu5894 hannnnah_j’s Biological Test(组合数学)
- hdu5894 hannnnah_j’s Biological Test(2016 acm/icpc 沈阳网络赛,组合数学)
- hdu5894 hannnnah_j’s Biological Test(数学)
- HDU5894分位置(组合数,lucas,乘法逆元)
- 组合数学
- 组合数学
- 组合数学
- 组合数学
- 组合数学
- 组合数学
- 组合数学
- 组合数学
- 组合数学
- 2018秋招笔试题_韩信点兵_C++
- [docker]docker常用命令
- 【Android笔记-异常-3】数字在TextView中显示一定要先转换为字符串。String.valueOf(数字)
- WPF 批量读取文件夹下TXT文件写入EXCEL
- Kotlin中的const常量
- 组合数学-HDU5894
- Javascript面向对象编程,定义类(class)的三种方法
- 程序之间共享数据SharedPreferences(一)
- 为什么多个客户端可以连接服务器的同个端口?
- 一些文件夹
- LeetCode 217. Contains Duplicate
- servlet的url-pattern匹配规则详细描述
- ucos-iii学习之ucos-iii的特性
- Elasticsearch Reference 5.5 中文翻译5