uva11481 Arrange the Numbers(错位排列)

来源:互联网 发布:双色球246红球计算法 编辑:程序博客网 时间:2024/05/14 21:36

关键词:错位排列
题意:求1-n的条件排列个数
条件为:前m个数中有恰k个数满足a[i]==i
解法:递推。
1.前m个数中有k个数满足a[i]==i,删除这k个数,题意转化为前n-k个数种前m-k个数满足a[i]!=i的排列个数。
结论:1-n的排列中前m个数错位排列的个数
dp[i][j]:1-i的排列中前j个数错位排列的个数
1.第j个数排列在(j,i]序列中:可以看做第j个数与除去第j位的前i-1位元素错位排列后,第j个元素与(j,i]序列位置中的元素交换位置:dp[i-1][j-1]*(i-j)
2.第j个数排列在[1,j)序列中:可以看做在[1,j)位置中选择一个位置k给j填。仍然去除第j个位置,但是选择的k位置可以错排,也可以不用错排,因此dp值应转化为:dp[i-1][j-2]*(j-1)
综上:dp[i][j]=dp[i1][j1](ij)+dp[i1][j2](j1)

拓展
1:n个数的错位排列个数Dn=(Dn1+Dn2)(n1)
证明:在1-n-1中选取一位,这一位既可以参与错排,也可以不参与错排(Dn1+Dn2);然后n放在第这一位,这一位上的数字放到第n位,因此,公式成立
错位排列的表达式Dn=[(n!/e)+0.5],即最接近(n!/e)的整数!
注:两个递推的原理相同,只不过一个是一维表达式,另一个是二维表达式

#include <stdio.h>#include <string.h>#include <set>#include <map>#include <algorithm>#include<vector>#include<complex>#include<iostream>#define pi acos(-1)#define X first#define Y second#define ll long long#define MP(x,y) make_pair((x),(y))#define INF 0x3f3f3f3fconst ll mod = 1000000007;using namespace std ;const ll maxn = 1000+10;ll  t,n,m,k;ll dp[maxn][maxn];ll c[maxn][maxn];ll C(ll a,ll b){    if(a==b||b==0||a==0) return c[a][b]=1;    if(c[a][b]!=-1) return c[a][b];    else return c[a][b]=(C(a-1,b)+C(a-1,b-1))%mod;}void init(){    memset(c,-1,sizeof(c));    memset(dp,0,sizeof(dp));    dp[0][0]=1;    for(ll i=1;i<maxn-5;i++){        dp[i][0]=(dp[i-1][0]*i)%mod;        for(ll j=1;j<=i;j++){            dp[i][j]=(dp[i-1][j-1]*(i-j))%mod;            if(j>=2) dp[i][j]=(dp[i][j]+(dp[i-1][j-2]*(j-1))%mod)%mod;        }    }}int main(){    init();    scanf("%lld",&t);    for(ll cas=1;cas<=t;cas++){        scanf("%lld%lld%lld",&n,&m,&k);        printf("Case %lld: %lld\n",cas,(C(m,k)*dp[n-k][m-k])%mod);    }    return 0;}
0 0
原创粉丝点击