UVALive 6469 Deranged Exams 组合数学+容斥原理

这个题目的大概意思是:给n个座位。每个座位都有对应的人。问:至少前k个座位都坐错的种数。


直接求至少前k个座位都坐错的话有点难求。。

直接求总数-反例

把问题转换为:求至多有前k个座位坐对的总数。

假设有n=7 k=3

我们求前1个座位坐对的总数为:

C(3,1)*A(6,6)

但是考虑到这样的话会把1 3 1 2 2 3给算重

要减去1 2 1 3 2 3的总数。就是要减去C(3,2)*A(5,5)

但是减去的话又会多减去2 3的情况所以又要加上C(3,3)*A(4,4)

然后我们看一下

C(3,1)*A(6,6)-C(3,2)*A(5,5)+C(3,3)*A(4,4)


基本上就这样了。详情看代码

//First Edit Time:	2014-07-15 19:15
//Last Edit Time:	2014-07-15 19:35
//Filename:E.cpp
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
LL c[20][20];
LL a[20];
int main()
{
    a[0]=1;
    a[1]=1;
    c[1][0]=c[1][1]=1;
    for(int i=2;i<=17;i++)
    {
        a[i]=a[i-1]*i;
        c[i][0]=c[i][i]=1;
        for(int j=1;j<i;j++)
            c[i][j]=c[i-1][j]+c[i-1][j-1];
    }
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int cas,n,k;
        scanf("%d%d%d",&cas,&n,&k);
        if(k==0)
        {
            printf("%d %lld\n",cas,a[n]);
            continue;
        }
        LL  ans=0;
        for(int i=1;i<=k;i++)
        {
            if(i&1) ans+=(c[k][i])*a[n-i];
            else ans-=(c[k][i])*a[n-i];
        }
        printf("%d %lld\n",cas,a[n]-ans);
    }
    return 0;
}



你可能感兴趣的:(UVALive 6469 Deranged Exams 组合数学+容斥原理)