codeforces 932E Team Work

codeforces 932E

题目描述

\(\sum_{i=1}^{n}{(^n_i)i^k}\space mod\space10^9+7\)

思路

本题\(n\)的范围很大\((n\le10^9)\),但\(k\)在可接受的范围内\((k\le5000)\),我们可以尝试从\(k\)入手。

构造\((1+x)^n=\sum_{i=0}^n{(^n_i)x^i}\)

对等式两边求导并同乘\(x\),得
\[ nx(1+x)^{n-1}=\sum_{i=1}^n\big(^n_i\big)ix^i \]
重复操作,得
\[ x\frac{\mathrm{d}}{\mathrm{d}x}(nx(1+x)^{n-1})=\sum_{i=1}^n\big(^n_i\big)i^2x^i \]

我们发现,当操作\(k\)次并代入\(x=1\)时就是我们想要的答案。问题转化为求左式的值。但是我们难以直接得出一个复合函数的导数,因此考虑递推转移:令\(f[a][b][c]\)\(x^b(1+x)^c\)经过a次操作的导数值,则我们要求的是\(f[k][0][n]\)

\(x^b(1+x)^c\)进行一次操作,得:
\[ bx^b(1+x)^c+cx^{b+1}(1+x)^{c-1} \]
得到转移\(f[a][b][c]=b\times f[a-1][b][c] + c\times f[a-1][b+1][c-1]\)。这一转移可以用记忆化搜索来实现。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MAXK = 5000 + 10;
const int MOD = 1000000007;

ll f[MAXK][MAXK];

ll qpow(ll a, ll b)
{
    ll ans = 1;
    while (b) {
        if (b & 1)
            ans = ans * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return ans;
}

ll dp(int a, int b, int c)
{
    if (f[a][b] != -1)
        return f[a][b];
    ll& now = f[a][b];
    now = 0;
    if (a == 0) 
        return now = qpow(2, c);
    if (c == 0)
        return now = qpow(a, b);
    return now = (b * dp(a - 1, b, c) + c * dp(a - 1, b + 1, c - 1)) % MOD;
}

int main()
{
    ll n, k;
    cin >> n >> k;
    memset(f, -1, sizeof(f));
    cout << dp(k, 0, n);
}

猜你喜欢

转载自www.cnblogs.com/erro/p/9037658.html
今日推荐