容斥原理--计算错排的方案数 UVA 10497

错排问题是一种特殊的排列问题。

模型:把n个元素依次标上1,2,3.......n,求每一个元素都不在自己位置的排列数。

运用容斥原理,我们有两种解决方法:

1.

总的排列方法有A(n,n),即n!,设Ai 表示数i在第i个位置的全体排列,显然有Ai =(n-1)!。

同理可得Ai∩Aj=(n-2)!,那么每一个元素都不在原来位置的排列就有n!-C(n,1)*(n-1)!+C(n,2)*(n-2)!-.....+(-1)^n *C(n,n)*1!。

也就是n!*(a-1/1!+1/2!-1/3!+1/4!-.....+(-1)^n *1/n!)。

我们只要预处理n的阶乘就可以得到答案。

2.

用DP的思想来运用容斥原理。

设1,2......错排的方案数是dp[n],当我们任取一个数i来使之错位时都有两种情况:

①:数i先与其他n-1个数之一互换,然后剩下n-2个错排..dp[n]=(n-1)*dp[n-2]。

②:除数i外其他n-1个数错排,再从这n-1个数中选一个和i互换..dp[n]=(n-1)*dp[n-1]。

显然这两种错排形式是相互独立且互斥的,运用加法定理,那么我们有:dp[1]=0,dp[2]=1,dp[n]=(n-1)*(dp[n-1]+dp[n-2])。

--------

注意:

当n比较大时,错排的方案数也会变得相当大!所以一般错排的题都会用高精度。

【模板题】UVA 10497

Children are always sweet but they can sometimes make you feel bitter. In this problem, you will see
how Tintin, a ve year's old boy, creates trouble for his parents. Tintin is a joyful boy and is always
busy in doing something. But what he does is not always pleasant for his parents. He likes most to play
with household things like his father's wristwatch or his mother's comb. After his playing he places it
in some other place. Tintin is very intelligent and a boy with a very sharp memory. To make things
worse for his parents, he never returns the things he has taken for playing to their original places.
Think about a morning when Tintin has managed to `steal' three household objects. Now, in how
many ways he can place those things such that nothing is placed in their original place. Tintin does not
like to give his parents that much trouble. So, he does not leave anything in a completely new place;
he merely permutes the objects.
Input
There will be several test cases. Each will have a positive integer less than or equal to 800 indicating
the number of things Tintin has taken for playing. Each integer will be in a line by itself. The input
is terminated by a `-1' (minus one) in a single line, which should not be processed.
Output
For each test case print an integer indicating in how many ways Tintin can rearrange the things he has
taken.
Sample Input
2
3
4
-1
Sample Output
1
2
9

题意:

问n个数错排的方案数。

 

错排的思路如上,AC代码用的是思路2。

AC code:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll m=1e10;
struct Bigint{
    ll s[1010];
    ll l;
    Bigint()
    {
        l=0;
        memset(s,0,sizeof(s));
    }
    void operator *=(int x)
    {
        ll d=0;
        for(int i=0;i<=l;i++)
        {
            d+=s[i]*x;
            s[i]=d%m;
            d/=m;
        }
        while(d)
        {
            s[++l]=d%m;
            d/=m;
        }
    }
    void print()
    {
        printf("%llu",s[l]);
        for(int i=l-1;i>=0;i--)
        {
            printf("%010llu",s[i]);
        }
    }
    void set(ll x)
    {
        s[l]=x%m;
        x/=m;
        while(x)
        {
            ++l;
            s[l]=x%m;
            x/=m;
        }
    }
}dp[1010];
Bigint operator +(Bigint b,Bigint& a)
{
    ll d=0;
    b.l=max(b.l,a.l);
    for(int i=0;i<=b.l;i++)
    {
        b.s[i]+=(d+a.s[i]);
        d=b.s[i]/m;
        b.s[i]%=m;
    }
    if(d)
    {
        b.s[++b.l]=d;
    }
    return b;
}
int n;
int main()
{
    //freopen("input.txt","r",stdin);
    dp[1].set(0);
    dp[2].set(1);
    for(int i=3;i<=800;i++)
    {
        dp[i]=dp[i-1]+dp[i-2];
        dp[i]*=(i-1);
    }
    while(~scanf("%d",&n)&&n!=-1)
    {
        dp[n].print();
        printf("\n");
    }
    return 0;
}
View Code

 

posted on 2019-08-28 13:22  Caution_X  阅读(502)  评论(0编辑  收藏  举报

导航