CF622F:k番目の電力の合計

書き込み(O(N)\)\の参照としてコード。

これは、もっと何かピットです。

ので、配列の中でいくつかを開くために私のコード私は怠け者です理解を容易にします。

溶液

まず、我々はポジティブなソリューションを(ラグランジュ特定の差が語られていない)を見つけます。

維持する必要性を探します:

乗法逆元階乗

それからですので、\(1 \)を開始、必要なスペースは、大規模ではありませんので、することができます\(O(K)\)処理し、次の。

\(\ PRODの\のlimits_ {i = 1} ^ NX-iは、\)

これは、各要素は、ルーチン、それによれば、さらに再反転元によって、得ることができ、逆ではありません。

\(N当量のK + 2 \ \)を応答します

厳密な時間複雑性を確保するためである\(O(K)\) これは線形篩であるべきです。

コード

#include <cstdio>
using namespace std;
const int N = 1000000 + 5, mod = 1000000007;
inline int mul (int a, int b) {return 1LL * a * b % mod;}
inline int add (int a, int b) {return a + b >= mod ? a + b - mod : a + b;}
inline int mns (int a, int b) {return a - b < 0 ? a - b + mod : a - b;}
inline int qpow (int u, int v) {
    int tot = 1, base = u % mod;
    while (v) {
        if (v & 1) tot = mul (tot, base);
        base = mul (base, base);
        v >>= 1;
    }
    return tot;
}
int x, k;
struct DuLiu {
    int pri[N + 5], tot, res[N + 5];
    bool vis[N + 5];
    inline void init () {
        int n = k + 2;
        res[1] = 1;
        for (int i = 2; i <= n; ++i) {
            if (!vis[i]) {
                pri[++tot] = i;
                res[i] = qpow (i, k);
            }
            for (int j = 1; j <= tot; ++j) {
                if (pri[j] * i > n) break;
                vis[i * pri[j]] = 1;
                res[i * pri[j]] = mul (res[i], res[pri[j]]);
                if (i % pri[j] == 0) break;
            }
        }
        for (int i = 2; i <= n; ++i) res[i] = add (res[i - 1], res[i]);
    }
}num;
int fac[N + 5], fac_prod[N + 5], fac_prod_inv[N + 5], extra, mid[N + 5], mid_prod[N + 5], mid_prod_inv[N + 5], mid_inv[N + 5];
inline void init_mid () {
    int n = k + 2;
    for (int i = 1; i <= n; ++i) mid[i] = x - i; mid[0] = x;
    mid_prod[0] = 1; for (int i = 1; i <= n; ++i) mid_prod[i] = mul (mid_prod[i - 1], mid[i]);
    mid_prod_inv[n] = qpow (mid_prod[n], mod - 2);
    for (int i = n - 1; i >= 0; --i) mid_prod_inv[i] = mul (mid_prod_inv[i + 1], mid[i + 1]);
    for (int i = 1; i <= n; ++i) mid_inv[i] = mul (mid_prod_inv[i], mid_prod[i - 1]);
    mid_inv[0] = qpow (x, mod - 2);
}
inline void Lagrange () {
    int ans = 0, n = k + 2;
    for (int i = 1; i <= n; ++i) {
        int tmp = 1, f = 1;
        tmp = mul (tmp, mul (fac_prod_inv[i - 1], i - 2 >= 0 ? fac_prod[i - 1 - 1] : 1));
        tmp = mul (tmp, mul (fac_prod_inv[n - i], n - i - 1 >= 0 ? fac_prod[n - i - 1] : 1));
        if ((n - i) % 2 == 1) f *= -1;
        int liujuakioi = mid_prod[n];
        tmp = mul (tmp, mul (liujuakioi, mid_inv[i]));
        tmp = mul (tmp, num.res[i]);
        if (f > 0) ans = add (ans, tmp);
        else ans = mns (ans, tmp);
    }
    printf ("%d\n", ans);
}
int main () {
    scanf ("%d%d", &x, &k);
    num.init ();
    if (x <= k + 2) {printf ("%d\n", num.res[x]); return 0;}
    fac[0] = 1; for (int i = 1; i <= N; ++i) fac[i] = mul (fac[i - 1], i);
    fac_prod[0] = 1; for (int i = 1; i <= N; ++i) fac_prod[i] = mul (fac_prod[i - 1], fac[i]);
    fac_prod_inv[N] = qpow (fac_prod[N], mod - 2);
    for (int i = N - 1; i >= 0; --i) fac_prod_inv[i] = mul (fac_prod_inv[i + 1], fac[i + 1]);
    init_mid();
    Lagrange ();
    return 0;
} 

結論

詳細は、あまりにも前に数回を支払います。

\(ラグランジュ\)変数内の関数を使用するには、エラーが発生しやすい(実際に私はあまりにも面倒、他のより便利アップの配列の一見だけでは逆階乗を書きました)。

おすすめ

転載: www.cnblogs.com/ChiTongZ/p/11304841.html