hdu 5894 分位置(环上组合,16沈阳网络赛)

hdu5894

题目大意

一个大小为 n的环,选 m 个位置涂黑,要求相邻两个黑点之间至少间隔 k个白点,问方案数。

分析

1. 思路一(较复杂)

令f(n,m)表示n个座位排成一排,选m个,相邻间隔不小于k个方案数。
将这环上n个座位编号从1到n.
①从1开始选的第一个>k :方案数为f(n-k,m)
②从1开始选的第一<=k :方案数为f(n-2k-1,m-1)
剩下问题就转换成求f(n,m)了。我们可以考虑插点法来转化问题,对于m个涂黑的座位,在它们之间(包括两边)m+1个间隔插入n-m个空座位:
x1+x2+...+xm+1=nm(x1>=0,x2>=k...xm>=k,xm+1>=0)
=> x1+x2+...+xm+1=nm+2k(xi>=k)
我们还可以通过引入一个松弛变量y来使得xi>=1(因为这是我们熟悉的模型)y=(k-1)*(m+1);
x1+x2+...+xm+1=nm+2ky(xi>=1)
再用插板法,n-m+2k-y个球分成m+1堆每堆至少一个有多少种分法。这个答案就是 Cmnm+2ky1=Cmn+kkm
得到

f(n,m)=Cmnkm+k

=>f(n-k,m)= Cmnkm
=>f(n-2k-1,m-1)= Cm1nkm1
Ans=Cmnkm+kCm1nkm1=nCm1nkm1m

然后用乘法逆元解决除法取模的问题。

1. 思路二

引用别人的分析)首先确定第一个人的位置,第一个人可以从n个椅子中任选一个,然后剩余n-1个椅子。因为人的间隔至少k个椅子,所以从这些符合要求的间隔距离的椅子抽出k*m个,然后剩下的m-1个人就可以随便从剩下的椅子人选了。可以想象成每个人和k个座位绑在一起,一旦这个人有了座位,他后面自动添加这k个座位。
那么第一个人从n个座位中选择一个,并且抽走了k*m个,那么剩下n-1-k*m个座位,在这之中选m-1个作为给其余人座,总数为 sum=nCm1nkm1 ,因为这里的人是无差别的。比如有3个人,假设他们坐的位置是(2,4,7),那么,(4,2,7),(7,2,4)是重复计算的,所有sum/m。

总结

第一种思路是不断的将问题转化为我们熟悉的问题,先是想办法把环拆成链,然后在链上将至少间隔k个的问题转化成至少间隔1的问题。
第二种思路可以看作是先将某一个人(就是分析里的第一个人)看作是独特的。由于有m个人,所以结果sum/m。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod=1000000007;
LL qmod(LL x,int n)//快速幂取模
{
      LL ans=1;
      for(;n;n>>=1)
      {
            if(n&1)ans=(ans*x)%mod;
            x=x*x%mod;
      }
      return ans;
}
LL C(int n,int m)//组合数取模
{
      if(m>n)return 0;
      LL ans=1;
      for(int i=1;i<=m;i++)
      {
            ans=ans*((n-m+i)*qmod(i,mod-2)%mod)%mod;
      }
      return ans;
}
int main()
{

     int T;
     LL n,m,k;
     scanf("%d",&T);
     LL ans;
     while(T--)
     {
           ans=0;
           scanf("%lld%lld%lld",&n,&m,&k);
           if(m==1)printf("%lld\n",n);
           else printf("%lld\n",(C(n-k*m-1,m-1)*n%mod)*qmod(m,mod-2)%mod);
     }
     return 0;
}

扩展

关于组合取模和乘法逆元问题请参考:
欧几里得算法、扩展欧几里得、乘法逆元
组合取模问题与Lucas定理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值