排座位

题目链接: http://exercise.acmcoder.com/online/online_judge_ques?ques_id=3370&konwledgeId=40

解题思路: 我们可以先把m个人排好,方案数m!,然后考虑在两个人之间插入空格,假设在第一个人前面插入x0个空格,在第1个人和第2个人之间插入x1个空格。。。

那么我们有: x0+x1+x2+....+xm=n-m (除去m个人后,只剩下n-m个位置)。若要符合题意的要求使得,任何两个人都不相邻,则,xi>=1 i=1,2,3,...,m-1。

由于第一个人和最后一个人是可以环形相邻的,所以需要分别考虑:

  1.  x0==0,那么需要xm>=1
  2. xm==0,那么需要x0>=1
  3.  x0>=1 && xm>=1

先考虑第三种情况,即x0+x1+x2+...+xm=n-m,这个可以用隔板法求出排列数。例如x1+x2+x3=5,可以把5写成5=1+1+1+1+1,现在需要在4个"+"号中选择两个,使得最后是三个数相加,所以是C(4-1, 3-1)。对于我们的问题有ans=C(n-m-1, m)  (因为共m+1个数)

对于第1,2这两种情况,相当于x1+x2+...+m=n-m,解法同上,ans=C(n-m-1, m-1)

最后把所有的结果加一起就好。最终的结果就是:m!(C(n-m-1,m) + 2*C(n-m-1, m-1))

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 const int MAXN = 100005;
 6 const LL MOD7 = 1e9+7;
 7 
 8 LL n,m;
 9 LL pow(LL a, LL b, LL MOD)
10 {
11     LL ans = a%MOD;
12     LL res=1LL;
13     while (b)
14     {
15         if (b&1) res=res*ans%MOD;
16         ans=ans*ans%MOD;
17         b>>=1;
18     }
19     return res;
20 }
21 
22 LL inverse(LL a, LL p)
23 {
24     return pow(a,p,p-2);
25 }
26 
27 void solve(LL n, LL m)
28 {
29     LL ans=1LL;
30     for (int i=1;i<=m-1;++i) ans=ans*(n-m-1-i+1)%MOD7;
31     LL res=0LL;
32     res=(ans*m*2%MOD7+ans*(n-m*2)%MOD7)%MOD7;
33     printf("%lld\n",res);
34 }
35 
36 int main()
37 {
38 #ifndef ONLINE_JUDGE
39     freopen("test.txt","r",stdin);
40 #endif // ONLINE_JUDGE
41     int Case;
42     scanf("%d",&Case);
43     while (Case--)
44     {
45         scanf("%lld%lld",&n,&m);
46         if (n<2*m) printf("0\n");
47         else if (m==1LL) printf("%lld\n",n);
48         else solve(n,m);
49     }
50     return 0;
51 }

 

posted @ 2018-04-23 12:45  只会一点暴力  阅读(256)  评论(0编辑  收藏  举报