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

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

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

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

写得好看一点就是

s ! i = 1 s q ( 1 ) i × ( s q i ) × ( s i ) !

具体实现看代码吧,不过我的代码比较奇怪, ( i j ) 其实是 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;
}

猜你喜欢

转载自blog.csdn.net/ymzqwq/article/details/81252341