lightoj 1095 - Arrange the Numbers (错排数)

题意:

求n个数的排列,前m个中有k个在自己的位置上的方法数。

思路:

设D[n]为n个元素的错排数.

于是我们有D[1] = 0 D[2] = 1;

D[n] = (D[n-1] + D[n-2]) * (i-1)

考虑问题本身,我们首先从前m个数选k个数不动.即C(m,k)。对于没有选的前m中的m-k个数肯定是参与了错排,而后面n-m个数中参加错排的个数不定,所以我们枚举一个后面n-m个数中选出i(0 <= i <= n - m)个数有没有参与错排。总共就有n-k-i参与了错排.

综上所述,ans公式就是C[m][k] * sigama(C[n-m][i] * D[n-k-i]) % mod;

预处理出组合数和错排数,然后就乱搞了。

注意有个坑点。。D[0]要赋值为1

参考code:

/*
 #pragma warning (disable: 4786)
 #pragma comment (linker, "/STACK:0x800000")
 */
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <algorithm>
#include <iterator>
#include <utility>
using namespace std;

template< class T > T _abs(T n){
    return (n < 0 ? -n : n);
}
template< class T > T _max(T a, T b){
    return (!(a < b) ? a : b);
}
template< class T > T _min(T a, T b){
    return (a < b ? a : b);
}
template< class T > T sq(T x){
    return x * x;
}
template< class T > T gcd(T a, T b){
    return (b != 0 ? gcd<T>(b, a%b) : a);
}
template< class T > T lcm(T a, T b){
    return (a / gcd<T>(a, b) * b);
}
template< class T > bool inside(T a, T b, T c){
    return a<=b && b<=c;
}
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define F(i, n) for(int (i)=0;(i)<(n);++(i))
#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
#define repok(i, s, t, o) for(int (i)=(s);(i)<=(t) && (o);++(i))
#define MEM0(addr) memset((addr), 0, sizeof((addr)))
#define MP(x, y) make_pair(x, y)
#define REV(s, e) reverse(s, e)
#define SET(p) memset(pair, -1, sizeof(p))
#define CLR(p) memset(p, 0, sizeof(p))
#define MEM(p, v) memset(p, v, sizeof(p))
#define CPY(d, s) memcpy(d, s, sizeof(s))
#define READ(f) freopen(f, "r", stdin)
#define WRITE(f) freopen(f, "w", stdout)
#define SZ(c) (int)c.size(
#define PB(x) push_back(x)
#define ff first
#define ss second
#define ll long long
#define ld long double
#define pii pair< int, int >
#define psi pair< string, int >
#define ls l,mid,rt<<1
#define rs mid+1,r,rt<<1|1
#define debug(x) cout << #x << " = " << x << endl
const double PI = acos(-1.0);
const int inf = 1<<30;

const int maxn = 1000;
const int mod = 1000000007;

int m,n,k;
ll D[maxn+5];
ll C[maxn+5][maxn+5];
void init(){
    C[0][0] = 1;
    rep(i,1,maxn){
        C[i][0] = C[i][i] = 1;
        rep(j,1,i-1) C[i][j] = (C[i-1][j-1] + C[i-1][j]) % mod;
    }
    D[1] = 0,D[0] = D[2] = 1;
    rep(i,3,maxn) D[i] = (i-1) * (D[i-1] + D[i-2]) % mod;
}
ll solve(int n,int m,int k){
    ll ans = 0;
    rep(i,0,n-m) ans = (ans + C[n-m][i] * D[n-k-i]) % mod;
    return ans * C[m][k] % mod;
}
int main(){
    //READ("in.txt");
    int t,kase = 1;
    scanf("%d",&t);
    init();
    while(t--){
        scanf("%d%d%d",&n,&m,&k);
        printf("Case %d: %llu\n",kase++,solve(n,m,k));
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-26 13:13:32

lightoj 1095 - Arrange the Numbers (错排数)的相关文章

LightOJ - 1095 - Arrange the Numbers(错排)

链接: https://vjudge.net/problem/LightOJ-1095 题意: Consider this sequence {1, 2, 3 ... N}, as an initial sequence of first N natural numbers. You can rearrange this sequence in many ways. There will be a total of N! arrangements. You have to calculate t

lightoj 1095 - Arrange the Numbers(dp+组合数)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1095 题解:其实是一道简单的组合数只要推导一下错排就行了.在这里就推导一下错排 dp[i]=(i-1)*dp[i-2](表示新加的那个数放到i-1中的某一个位置然后那个被放位置的数放在i这个位置就是i-2的错排)+(i-1)*dp[i-1](表示新加的那个数放到i-1中的某一个位置然后用那个位置被占的数代替i这个位置的数就是i-1的错排) #include <iostream

错排数

考虑如下问题: 若1...n的一些全排列满足第1个不是1,第2个不是2,...,第n个不是n,这样的序列有多少个? 记答案为fn . 考虑第1个位置的数,若它是x: 1. 若第x位是1,则剩下的就是n-2个数的错排数fn-2 2.否则,就相当于n-1个数的错排数(因为第2个不是2,...第x个不是1,...,第n个不是n,那就可以把1看作x)fn-1 又因为x有n-1种选法,所以fn=(n-1)(fn-1+fn-2) 有f0=1,f1=0 这个序列称作错排数. 它的前几项为1, 0, 1, 2,

E - 不容易系列之(4)――考新郎 错排数公式

国庆期间,省城HZ刚刚举行了一场盛大的集体婚礼,为了使婚礼进行的丰富一些,司仪临时想出了有一个有意思的节目,叫做"考新郎",具体的操作是这样的:  首先,给每位新娘打扮得几乎一模一样,并盖上大大的红盖头随机坐成一排; 然后,让各位新郎寻找自己的新娘.每人只准找一个,并且不允许多人找一个. 最后,揭开盖头,如果找错了对象就要当众跪搓衣板... 看来做新郎也不是容易的事情... 假设一共有N对新婚夫妇,其中有M个新郎找错了新娘,求发生这种情况一共有多少种可能. Input输入数据的第一行是

Light oj 1095 - Arrange the Numbers (组合数学+递推)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1095 题意: 给你包含1~n的排列,初始位置1,2,3...,n,问你刚好固定前m个数中的k个数的位置,问你有多少中排列方案.(比如5 3 2有1 4 3 2 5这种方案,1和3固定了) 思路: 前m个取k个就是C(m, k)个方案.然后就是类似错排的思想,设dp[i]为i个数在初始位置各不相同.其中的组合数用逆元算出. ans = dp[m - k] * C(n - m,

(Java) LeetCode 386. Lexicographical Numbers —— 字典序排数

Given an integer n, return 1 - n in lexicographical order. For example, given 13, return: [1,10,11,12,13,2,3,4,5,6,7,8,9]. Please optimize your algorithm to use less time and space. The input size may be as large as 5,000,000. 一道没有标签的题,第一个想到的思路就是深度优先

LightOJ 1095 Arrange the Numbers-容斥

给出n,m,k,求1~n中前m个正好有k个在原来位置的种数(i在第i个位置) 做法:容斥,先选出k个放到原来位置,然后剩下m-k个不能放到原来位置的,用0个放到原来位置的,有C(m-k,0)*(n-k)!种 - 1个放原来位置的,有C(m-k,1)*(n-k-1)!种+...-... 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int N=1e3+10; 5 const in

Light OJ 1095 Arrange the Numbers

给定n,m,k,要求在n的全排列中,前m个数字中恰好有k个位置不变,有几种方案?首先,前m个中k个不变,那就是C(m,k),然后利用容斥原理可得 ans=ΣC(m,k)*(-1)^i*C(m-k,i)*(n-k-i)! (0<=i<=m-k) 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream&g

RPG的错排

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8387    Accepted Submission(s): 3415 Problem Description 今 年暑假杭电ACM集训队第一次组成女生队,其中有一队叫RPG,但做为集训队成员之一的野骆驼竟然不知道RPG三个人具体是谁谁.RPG给他机会让他猜 猜,第一次猜:R是公主,P是草