[Codeforces 340E] Iahub and Permutations (容斥)

本文详细解析了一道关于排列组合的算法题目,核心是求解特定条件下的错排方案数。通过对错排公式进行容斥原理分析,并给出了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门
这个340E竟然是340e,让人觉得很诡异。。。

稍微分析一下就可以发现这题本质是求 s s 个数排列,有q个数可以随便排,其余错排的方案数。

回忆一下,我们证明错排通项公式的时候是怎么容斥的,其实这题也差不多。
就是总方案数 - 1个在原来位置上的方案数 + 2个在原来位置上的方案数 - 3个在原来位置上的方案数……
具体来说,有 i i 个在原来位置上的方案数,就是先在要错排的数里选i个放在原来的位置上,其余的数乱排。

写得好看一点就是

s!i=1sq(1)i×(sqi)×(si)! s ! − ∑ i = 1 s − q ( − 1 ) i × ( s − q i ) × ( s − i ) !

具体实现看代码吧,不过我的代码比较奇怪, (ij) ( i j ) 其实是 c[i+1][j+1] c [ i + 1 ] [ j + 1 ]

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=2001;
const int p=1e9+7;
int n,a[N],s,q,b[N];
LL mul[N],P[N],C[N][N],ans;

void read(int &x){
    char ch=getchar();x=0;int w=1;
    for(;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') w=-1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
    x*=w;
}

int main(){
    read(n);
    for(int i=1;i<=n;i++){
        read(a[i]);
        if (a[i]==-1) s++;
         else b[a[i]]=1;
    }
    for(int i=1;i<=n;i++) if (b[i]&&a[i]==-1) q++;

    mul[0]=1;
    for(int i=1;i<=n;i++) mul[i]=mul[i-1]*i%p;
    /*P[0]=1;P[1]=0;
    for(int i=2;i<=n;i++) P[i]=(n-1)*(P[i-1]+P[i-2])%p;*/
    C[0][0]=1;
    for(int i=1;i<=n+1;i++)
     for(int j=1;j<=n+1;j++)
      C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;

    ans=mul[s];int w=1;
    for(int i=1;i<=s-q;i++){
        w*=-1;
        ans=(ans+w*C[s-q+1][i+1]*mul[s-i]%p)%p;
    }

    cout<<(ans+p)%p;
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值