Codeforces Round #175 DIV2 E Positions in Permutations

来源:互联网 发布:都市天际线优化mod 编辑:程序博客网 时间:2024/05/22 02:03

题目链接

题意:对于某个排列p1,p2,...pn,位置i为good position当且仅当| pi - i | = 1,给你一个N,表示排列的元素个数,求满足恰好有K个good  position的排列的个数,对结果Mod 1000000007。 

思路:DP。首先很容易就可以想到如下的状态dp,用dp[i][j] 表示前i个位置中正好有j个位置是good position的种数。那么对于第i个位置,它就可以分成两大种情况:

a、第i个位置不是good ; 这时候我们可以很容易地实现状态转移:dp[i][j] = dp[i-1][j] 。

b、第i个位置是good。 这种情况又可以分成两种小情况:

b1.i的取值(即pi的值)是i-1; 但是这里有会带来另外一个问题,那就是i-1是否可用的问题,换句话说就是i-2位置是否已经将i-1这个数已经用掉了,所以我们可以再加入一维状态s来表示i的最后三位的状态。

b2.i的取值是i+1 ,此时可以不受前面限制地进行转移。


最后我们可以由dp求出整个排列中只有i个元素是good的值,记为sum[i],sum[i] *= fac[N-i],那么sum[i]就是至少有i个元素是good的总数,这里还特别需要注意的一点就是sum[i] = a[i] + C[i+1][i]*a[i+1] + C[i+2][i]*a[i+2]....,所以我们最后可以反解出a[K]。

代码:

#include <stdio.h>#include <string.h>typedef long long LL ;const int NN = 1010 ;const LL Mod = 1000000007  ;LL N , K ;LL dp[NN][NN][2][2][2] ;LL sum[NN] ;LL fac[NN] ;LL a[ NN ] ;LL C[NN][NN] ;void DP(){    memset( dp, 0 ,sizeof(dp) ) ;    dp[1][0][0][0][0] = 1 ;    if( N > 1 )        dp[1][1][0][0][1] = 1 ;    for(int i=1;i<N;i++){        for(int j=0;j<=i;j++){            for(int a=0;a<2;a++){                for(int b=0;b<2;b++){                    for(int c=0;c<2;c++){                        if( dp[i][j][a][b][c] == 0 )    continue ;                        int tmp = dp[i][j][a][b][c] ;                        dp[i+1][j][b][c][0] = ( dp[i+1][j][b][c][0] + tmp ) % Mod ;                        if( b == 0 )   dp[i+1][j+1][b][c][0] = ( dp[i+1][j+1][b][c][0] + tmp ) % Mod ;                        if( i+2<=N )   dp[i+1][j+1][b][c][1] = ( dp[i+1][j+1][b][c][1] + tmp ) % Mod ;                    }                }            }        }    }    for(int i=0;i<=N;i++){        sum[i] = 0 ;        sum[i] = dp[N][i][0][0][0] + dp[N][i][0][0][1] +                dp[N][i][0][1][0] + dp[N][i][0][1][1] +                dp[N][i][1][0][0] + dp[N][i][1][0][1] +                dp[N][i][1][1][0] + dp[N][i][1][1][1] ;        sum[i] %= Mod ;        sum[i] = sum[i] * fac[N-i] % Mod ;    }}int main(){    fac[1] = fac[0] = 1 ;    for(LL i=2;i<=1000;i++)    fac[i] = fac[i-1] * i % Mod ;    C[0][0] = C[1][0] = C[1][1] = 1 ;    for(int i=2;i<=1000;i++){        for(int j=0;j<=i;j++){            C[i][j] = C[i-1][j-1] ;            if( i-1>=j )    C[i][j] = (C[i][j] + C[i-1][j]) % Mod ;        }    }    while( scanf("%d %d",&N,&K) == 2 ){        DP() ;        a[N] = sum[N] ;        for(int i=N-1;i>=K;i--){            LL tmp = sum[i] ;            for(int j=i+1;j<=N;j++){                LL mid = C[j][i] * a[j] ;                mid %= Mod ;                tmp -= mid ;                if( tmp < 0 )   tmp += Mod ;            }            a[i] = tmp ;        }        printf("%d\n",(int)a[K] );    }    return 0 ;}


原创粉丝点击