洛谷 P1595 信封问题

经典的错位排列问题
题目描述

某人写了n封信和n个信封,如果所有的信都装错了信封。求所有信都装错信封共有多少种不同情况。

输入输出格式

输入格式:
一个信封数n

输出格式:
一个整数,代表有多少种情况。

输入输出样例

输入样例#1:
样例1:2

样例2:3
输出样例#1:
样例1:1

样例2:2


【分析】
容斥原理
ans=至少0个装错的-至少1个装错的+至少2个装错的+…-…+/-至少n个装错的

那么ans=Σ(i:0~n) C[n][i]*A[n-i]

C可以用递推关系式得到

C[n][k+1]=C[n][k]*(n-k)/(k+1)


【代码】

//错位排列 
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=100005;
int n,m;
ll c[mxn],fac[mxn],ans;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*f;
}
int main()
{
    int i,j,f=-1;
    n=read();
    c[0]=fac[0]=1;
    fo(i,0,9999) c[i+1]=c[i]*(n-i)/(i+1);
    fo(i,1,10000) fac[i]=fac[i-1]*i;
    fo(i,0,n)
    {
        f=-f;
        ans+=f*fac[n-i]*c[i];
    }
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值