【组合+错排】BZOJ4517(Sdoi2016)[排列计数]题解

题目概述

如果 ai=i i 是稳定的。给出 n,m ,求稳定数为 m n 的排列的个数。

解题报告

其实很简单……先选出 m 个稳定位置,然后另外 nm 强制不稳定。

强制不稳定也就是 aii ,即错排。


错排递推公式: D(0)=1,D(1)=0D(i)=(i1)[D(i2)+D(i1)]
推导:将 i 放在 k(ki) 上,有 i1 种方法。
然后若 k i 上,则剩下 i2 个数错排,方案数 D(i2)
否则就当 k i ,进行错排,方案数 D(i1)

示例程序

#include<cstdio>
#include<cctype>
using namespace std;
typedef long long LL;
const int maxn=1000000,MOD=1e9+7;

int te,n,m,fac[maxn+5],INV[maxn+5],D[maxn+5];

#define Eoln(x) ((x)==10||(x)==13||(x)==EOF)
inline char readc()
{
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF;return *l++;
}
inline int readi(int &x)
{
    int tot=0,f=1;char ch=readc(),lst='+';
    while (!isdigit(ch)) {if (ch==EOF) return EOF;lst=ch;ch=readc();}
    if (lst=='-') f=-f;
    while (isdigit(ch)) tot=(tot<<3)+(tot<<1)+ch-48,ch=readc();
    return x=tot*f,Eoln(ch);
}
void Make()
{
    INV[0]=INV[1]=1;for (int i=2;i<=maxn;i++) INV[i]=MOD-(LL)(MOD/i)*INV[MOD%i]%MOD;
    fac[0]=fac[1]=1;for (int i=2;i<=maxn;i++) fac[i]=(LL)fac[i-1]*i%MOD,INV[i]=(LL)INV[i-1]*INV[i]%MOD;
    D[0]=1;D[1]=0;for (int i=2;i<=maxn;i++) D[i]=(LL)(i-1)*(D[i-1]+D[i-2])%MOD;
}
inline int C(int x,int y) {if (x<y) return 0;return (LL)fac[x]*INV[y]%MOD*INV[x-y]%MOD;}
int main()
{
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    for (Make(),readi(te);te;te--)
    {
        readi(n);readi(m);if (n<m) {puts("0");continue;}
        printf("%lld\n",(LL)C(n,m)*D[n-m]%MOD);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值