【WC2017四校联考5】B君的宴请 题解

题目出自成都七中

题目大意

       n 把椅子排成一个环。
       现在要撤掉一部分,使得只剩下恰好 k 把椅子,并且剩下的任意两把椅子原先不相邻。
       若两种方案可以经过旋转、翻转互相等价,则认为本质相同。
       求本质不同的方案数 mod (1e9+7)

一个比较“正统”的思路

       首先把撤与不撤看作是01染色,0 表示撤,1 表示保留。

       考虑 burnside 引理。
       置换群大小为 2n,包括 n 个旋转置换和 n 个旋转+翻转置换。

       考虑 n 个旋转置换的不动点。
       对于第 i 个旋转置换(0<= i <=n-1),只有前面 d=gcd(i,n) 个元素可自由选择颜色。所以模型变成:长度为 d 的序列,我要分配 k’ 个黑色进去,要求任意两个黑色不相邻,且头尾不能同时为黑,的方案数。
       (这里因为原序列被划分成 n/d 段,所以这里 k’=k/(n/d),如果不能整除则视为该置换下不动点为 0。)
       那么这个模型就是一个组合数模型了。先不考虑头尾的限制。类似于挡板原理,我们把作为间隔的 k’-1 个白点抽出来,则 k’ 个黑点就没有不相邻的限制了,所以方案数就是 Ckd(k1) 。如果考虑头尾限制,则用总的减去头尾同时为黑的方案数,头尾同时为黑意味着次头和次尾同时为白,所以方案数是 Ck2(d4)((k2)1)

       考虑 n 个旋转+翻转置换的不动点。我们知道旋转+翻转置换可以等价为翻转置换。
       n 为奇数时,对称轴穿过一个点和一个空隙,设这个点为 A。由于空隙旁的两个点相邻,所以他们必为白色。若 k 为奇数,则 A 为黑色,A 的下一个点为白色,所以方案数是 Ck2(n22)(k21) 。若 k 为偶数,则 A 为白色,方案数类似。
       n 为偶数时,对称轴有两种,各有 n/2 条。一种是穿过两个点的,一种是穿过两个空隙的。分析方法类似,第一种对称轴要讨论 k 的奇偶性,第二种对称轴则要求 k 必须是偶数,否则为0。

一个大家都想到的思路

       这里就直接搬题解了。

       首先考虑 k 个椅子之间的一个置换(而不是像通常那样考虑 n 个椅子的情况)
       对于 k=1 和 k=2,可以直接计算答案。
       对于更大的 k 的情况,同样需要计算旋转和轴对称。
       如果 k 个椅子的位置确定,那么接下来的步骤就是将 n-k 个将要被撤掉的椅子,放进 k 个椅子的间隔中,使得每个间隔中至少有一个椅子。
       旋转的情况比较简单,就是和最大公约数相关。
       如果是轴对称的话,还需要根据 k 的奇偶性进行迚一步的讨论。
       如果 k 是奇数,那么对称之后一定是(k-1)/2 对 和 单独的一个点
       如果 k 是偶数,那么对称后可能是 k/2 对,还可能是 k/2-1 对和 2 个单独的点

代码

//用第一种方法的

#include<cstdio>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

typedef long long LL;

const int maxn=1e6+5;
const LL mo=1e9+7;

int n,k;

LL gcd(LL a,LL b) {return (b) ?gcd(b,a%b) :a ;}

LL mi(LL x,LL y)
{
    LL re=1;
    for(; y; y>>=1, x=x*x%mo) if (y&1) re=re*x%mo;
    return re;
}

LL fac[maxn],ny[maxn];
LL C(LL n,LL m)
{
    if (n<0 || m<0) return 0;
    return fac[n]*ny[m]%mo*ny[n-m]%mo;
}

int main()
{
    scanf("%d %d",&n,&k);
    if (n==1 || k==0) {printf("1\n"); return 0;}

    fac[0]=ny[0]=1;
    fo(i,1,n) fac[i]=fac[i-1]*i%mo, ny[i]=mi(fac[i],mo-2)%mo;

    LL ans=0;
    fo(i,1,n)
    {
        LL d=gcd(i,n);
        if (k%(n/d)!=0) continue;
        int kk=k/(n/d);
        if (d==1) continue;
        ans=(ans+C(d-(kk-1),kk)-C(d-4-(kk-3),kk-2)+mo)%mo;
    }
    if (n&1)
    {
        if (k&1) ans=(ans+C(n/2-2-(k/2-1),k/2)*n%mo)%mo;
            else ans=(ans+C(n/2-1-(k/2-1),k/2)*n%mo)%mo;
    } else
    {
        if (k%2==0) ans=(ans+C(n/2-2-(k/2-1),k/2)*(n/2)%mo)%mo;

        if (k&1)
        {
            ans=(ans+C(n/2-2-(k/2-1),k/2)*n%mo)%mo;
        } else
        {
            ans=(ans+(C(n/2-1-(k/2-1),k/2)+C(n/2-3-((k-2)/2-1),(k-2)/2))%mo*(n/2)%mo)%mo;
        }
    }
    ans=ans*mi(n*2,mo-2)%mo;

    printf("%lld\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值