HDU 2068 RPG错排 [错排公式]

1.题意:1到N的序列的排列中,元素位置与元素值相对应的情况(值为i的元素在某个排列中正好排在第i个位置)大于等于序列规模一半的情况,有多少个?

2.输入输出:每组数据一个数,N,规定输入以0结尾;

3.分析:原题意换句话说,就是针对1到N的全排列,错排元素的个数小于等于N的情况有多少;

那么,输出即为: HDU 2068 RPG错排 [错排公式]_第1张图片   其中F[i]表示1到i的错排方案数,后面一项为组合数,即选取i个错排;

这里推导一下错排公式,F[N]表示1到N的错排方案;第一步:选取N放到1到N-1之中任意一个位置,这样就有N-1种放法;第二步:分两种情况,不妨设第一步被N占据的位置为K,当位置N放置的数恰巧为K时,此时就相当于,K,N交换位置了,对应的错排方案为F[N-2];当位置N放置的数不为K时,此时的情况:1到K-1,K+1到N的位置要错排放置1到N-1的元素,N-1个 位置,N-1个元素,与F[N-1]的情况相比,只是多了一组(数K与位置N)的对应,而且这里N不放置K,就等效于普通的情况下(数K与位置K)的错排情况;举个例子,位置12345,数12345,现在5放置在2的位置上,剩下数1234,位置1345,且位置5上不放2,这里和1234-1234的错排有什么区别么?把位置5当成位置2,反正也是2不放在位置5上,与1234-1234里2不放在位置2上等效;综上所述,错排公式为F[i]=(i-1)*(F[i-1]+F[i-2]),其中,F[1]=0,F[2]=1;

 1 # include 
 2 # include 
 3 using namespace std;
 4 const int MAXN=26;
 5 int dp[MAXN];
 6 int N;
 7 long long Cn(int n,int m)
 8 {
 9     if(n==0) return 1;
10     n=m-n>n?n:m-n;
11     long long up,down;
12     up=down=1;
13     for(int i=1;i<=n;i++)
14     {
15         up*=m-i+1;
16         down*=i;
17     }
18     long long res=up/down;
19     return res;
20 }
21 void Init()
22 {
23     dp[0]=1;
24     dp[1]=0;
25     dp[2]=1;
26     for(int i=3;i<15;i++)
27         dp[i]=(i-1)*(dp[i-1]+dp[i-2]);
28 }
29 int main()
30 {
31     Init();
32     while(scanf("%d",&N)!=EOF)
33     {
34         if(N==0) break;
35         long long res=0;
36         for(int i=0;i<=N/2;i++)
37             res+=dp[i]*Cn(i,N);
38         printf("%lld\n",res);
39     }
40     return 0;
41 }

 

转载于:https://www.cnblogs.com/cnXuYang/p/6665269.html

你可能感兴趣的:(HDU 2068 RPG错排 [错排公式])