您的位置:首页 > 其它

uva11481 Arrange the Numbers(错位排列)

2015-05-07 19:00 441 查看
关键词:错位排列

题意:求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[i−1][j−1]∗(i−j)+dp[i−1][j−2]∗(j−1)

拓展

1:n个数的错位排列个数Dn=(Dn−1+Dn−2)∗(n−1)

证明:在1-n-1中选取一位,这一位既可以参与错排,也可以不参与错排(Dn−1+Dn−2);然后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 0x3f3f3f3f
const 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: