srm 711 DerangementsDiv2(dp)

来源:互联网 发布:天津淘宝模特 编辑:程序博客网 时间:2024/05/11 04:30

题意:

1-n+m的数排列,要求前m个数p[i]!=i,问有多少种排列方式,对1e9+7取模


解题思路:

不会做,最后问的p神才会了。


dp状态是dp[i][j],表示i个数排列要求前j个数 错排的方案数。

转移dp[i][j]=(i-j)*d[i-1][j]+j*dp[i-1][j-1];

分别表示最后一个数放在后n个位置还是前m个位置的两种方法。


i=j的时候就是错排公式,要单独写。



代码:

#include <bits/stdc++.h>#define LL long longusing namespace std;const int maxn=55;const int mod=1e9+7;LL fa[202];int i, j;LL dp[105][104];;void init(){    fa[0]=1;    for(int i=1; i<=200; i++)    {        fa[i]=(fa[i-1]*(LL)i)%mod;    }    return;}struct  DerangementsDiv2{        LL i, j;    int count(int n, int m)     {        init();        memset(dp, 0, sizeof dp);        dp[0][0]=1, dp[1][1]=0, dp[2][2]=1;        for(i=3; i<=n+m; i++)        {            dp[i][i]=((i-1)*((dp[i-1][i-1]+dp[i-2][i-2]))%mod)%mod;        }        for(i=0; i<=n+m; i++)        {            dp[i][0]=fa[i];            if(i)dp[i][1]=((i-1)*fa[i-1])%mod;        }        for(i=1; i<=n+m; i++)        {            for(j=2; j<=m; j++)            {                if(i==j)continue;                dp[i][j]=(((i-j)*(dp[i-1][j]))%mod+ (j*dp[i-1][j-1])%mod)%mod;            }        }        return dp[n+m][m];            }};/*int main(){    DerangementsDiv2 a;    int x, y;    while(~scanf("%d %d", &x, &y))    a.count(x, y);        }*/


原创粉丝点击