【JZOJ 3466】选课

Description

你真的认为选课是那么容易的事吗?HYSBZ的ZY同志告诉你,原来选课也会让人产生一种想要回到火星的感觉。假设你的一周有n天,那么ZY编写的选课系统就会给你n堂课。但是该系统不允许在星期i和星期i+1的时候选第i堂课,也不允许你在星期n和星期一的时候选第n堂课。然后连你自己也搞不清哪种选课方案合法,哪种选课不合法了。你只想知道,你到底有多少种合法的选课方案。

Solution

这题用容斥原理来搞,
Wk 表示至少有k个位置是错位的方案数,
我们先选i个一定是错位的,再乘以剩下的所有排列方案即可,

首先来给容斥没有学好的孩纸们讲一下为什么是容斥:
以选至少两个错位时的来举例子,(红色的是先选的错位的,棕色的是另外选时选的,稍微红一点的是另外选时错位的)
这里写图片描述
而这种情况也会出现:
这里写图片描述
但我们发现这其实是一样的,所以要减掉 W3 ,但又会减重,所以又要加回 W4 ……,
所以是用容斥,
现在对于每个 Wk=(nk)!wkwk 为选k个一定错位的方案数,
对于每天,对应的错误的课为: (1,2),(2,3),.....,(n,1)
拆开来就是: 1,1,2,2,3,3,....,n,n
又因为拆开以后选的每一节课都一定可以对应一天,所以只要在这堆数中选即可,
现在要求的就是这 2n 个数围成的圆中(第一个,最后一个不能被同时选),选i个两两不相邻的数方案数(一节课不可以被选两次嘛),
这里引用LYD的解释方法
设黑色为选,白色不选:
这里写图片描述
我们让黑色吃掉它右边一个,最后一个不吃,就变成了(被吃的为灰色):
这里写图片描述
同样的,从下图也可以推出一个唯一的上图,
当然,当第一个和最后一个同时选的情况时不合法的要减掉,
所以就是

wk=Ck2nk+1Ck2(2n4)(k2)+1

化解一下:
wk=Ck2nknnk

于是就可以求出 Wi ,之后再用容斥搞一波,

复杂度: O(nT)T 为数据组数,


其实还有一种奇怪的递推方法,我不会!

Code

注意常数对程序带来的影响!!!
本题需卡常!!!

当然你打表也没人拦着你~

#include<cstdio>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const int N=200050,mo=1e9+7;
LL n,ans;
LL jc[N],jcn[N],ny[N];
LL ksm(LL q,int w)
{
    LL ans=1;q%=mo;
    while(w)
    {
        if(w&1)(ans*=q)%=mo;
        (q*=q)%=mo;w>>=1;
    }
    return ans;
}
LL C(int i,int j){return jc[j]*jcn[i]%mo*jcn[j-i]%mo;}
int main()
{
    jc[0]=jcn[0]=1;
    fo(i,1,N-2)jc[i]=(jc[i-1]*i)%mo,jcn[i]=ksm(jc[i],mo-2),ny[i]=ksm(i,mo-2);
    while(scanf("%lld",&n)!=EOF)
    {
        ans=0;
        if(n>1)fo(k,0,n)
        if(k&1)ans=(ans-2*n*ny[2*n-k]%mo*C(k,2*n-k)%mo*jc[n-k])%mo;
        else ans=(ans+2*n*ny[2*n-k]%mo*C(k,2*n-k)%mo*jc[n-k])%mo;
        printf("%lld\n",(ans+mo)%mo);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值