Infiniti

   :: 首页  :: 新随笔  ::  ::  :: 管理


https://www.lydsy.com/JudgeOnline/problem.php?id=2655
 
以上是对 dp 一小部分打的表。dp[ i ] [ j ]  含义为 前 i 个 数 中 选 j 个 的 价 值 总 和 ,  则转移 方程为 
 
dp [ i ] [ j ] = dp [ i -1 ] [ j ]+ dp [ i - 1 ]  [ j - 1 ]  *  j  *  i .  无非就两中情况,第 j 个 (不是 i) ,(是 i),
 
前一个是 直接 把 i - 1 个中选 j 个转移过来,后一个的含义是 i - 1 个 选了 j - 1个  第 j 个选 i  那么 之前的价值 就都需要  * i
 
并且 种 数 也会变多 , 一共选了 j 个数 那么 排列方式 即为  J! 种  ,由于前面累乘过来了所以这一次直接只需要* j 即可
 
但是 由于 m 较大 无法直接 dp 转移求出,根据达标规律发现 其为  dp [ i ] [ j ] 是关于 i 的最高次项 次数 为 2 * j 的 多项式
 
dp  [ j ] [ j ] = j ! * j !  最高次项为 2 * j 次的 归纳 得出 dp   [ i ] [ j ]为 2*j次的。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 1555
ll n,a,mod,dp[maxn][maxn],z,m,ans;
ll qpow(ll a,ll b)
{
    ll re=1;
    while(b)
    {
        if(b%2)
            re=(re*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return re;
}
int main()
{
    scanf("%lld%lld%lld",&a,&n,&mod);
    dp[0][0]=1;
    for(int i=1; i<=2*n; i++)
    {
        dp[i][0]=dp[i-1][0];
        for(int j=1; j<=n; j++)
            dp[i][j]=(dp[i-1][j-1]*i*j%mod+dp[i-1][j])%mod;
    }
    if(a<=2*n)
    {
        printf("%lld\n",dp[a][n]);
        return 0;
    }
    for(int i=0; i<=2*n; i++)
    {
        m=1,z=dp[i][n];
        for(int j=0; j<=2*n; j++)
        {
            if(i==j)continue;
            z=(z*(a-j)%mod+mod)%mod;
            m=(m*(i-j)%mod+mod)%mod;
        }
        ans=(ans+z*qpow(m,mod-2)%mod+mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

  

posted on 2019-01-13 00:12  自由缚  阅读(190)  评论(0编辑  收藏  举报