8.27奇跡の旅

問題の意味

サイズのすべてについて\(K \)であり、正の整数で再設定が必要です\(\ sum_ {i = 1 } ^ ka_i = N \)は

上記の要件を満たす定義正の整数は、重量設定された重み値であってもよい
\ [\ sum_ {i = 1
} ^ K a_iを^ M \] 条件を満たす求め所有値が設定され、ダイ\(10 ^ 7 + 9 \)

実際には、luogu上の元のタイトルがあり、\(P4977 \) その質問には、あなたはまた、配列の最適化をスクロールする必要があるデータの広い範囲


ソリューション

重みが計算される追加ので、我々は、値の各別個の部分の重量を計算することができます

例えば、数\(a_iを\)

それは、コレクションのすべてに表示され、ある回数\(cnt_i \)

次いで数\(a_iを\)の貢献である\(a_iを^ Mの\回cnt_i \)

質問は今見つける方法です\(cnt_iを\)

この問題について再び変換し、私たちがすることができます(\ O(N))を\回数を列挙するために、この数は、コレクションの中に表示されます\(X \)の回数を掛け、表示されます\(X \に)セットの数を、それが加算されます最終的な答えとして

今の出現を見つけるために変換され、\(X \)のセット数を

セット([K [N] Fは\ \]) の加重値である(N \)\、合計\(K \)次に、要素のセットの数は、少なくとも発生の回数\(X \)のセット数すなわち、([NXの\時間a_iをF \ \] [KX])

しかし、これは、少なくともの出現ものです\(X \)回、ない正確に\(X \)

それを解決するためにどのような問題

これは、インクルージョン排除していると考えられるが、もっと簡単な方法があります

私たちの最後の要件がある\(cnt_iが\) オリジナルのアイデアは、出現数を乗じた発生回数は、数字のセットです。

今、私たちはちょうど出現回数を蓄積する必要があるコレクションの数であります

これは、それぞれの層を追加することに相当し、プラスすべての答えの統計に終了しました

(最後の時間であることが保証)への変換の問題は、私たちの仕事は、今見つけることです([n]は[K fを\ \])

考え\(DP \) 特定の問題を参照してすることができる\(P1025の\)の分割数

\(DP \)は非常に巧妙なアイデアです

我々は二つのカテゴリーに述べる:設定しているもの\(1 \)は、この要素がクラスではない、2が追加移し、

具体的には、

\([N] [K] = F [N] [K] + F F [N-1] [K-1] \)

このカテゴリは内に設定されている\(1 \)

\([N] F [K] = F [N] [K] + F [NK] [K] \)

このクラスは、セット内にない\(1 \)番号、と見ることができる\(F [NK] [K ] \) のすべての要素に加えに\(1 \)のコレクションを確保するために、なし\(1 \) A


コード

#include <cstdio>
#include <cctype>

using namespace std;

const int mod = 1e9 + 7;

int n, k, m;

int f[5010][5010];

inline int qpow(int x, int y) {
    int res = 1;
    while (y) {
        if (y & 1)  res = 1LL * res * x % mod;
        x = 1LL * x * x % mod, y >>= 1; 
    }
    return res;
}

int main() {
    
    freopen("set.in", "r", stdin);
    freopen("set.out", "w", stdout);
    
    scanf("%d%d%d", &n, &k, &m);
    
    for (int i = 1; i <= n; ++i)    f[i][1] = 1;
    for (int i = 2; i <= n; ++i) {
        for (int j = 2; j <= k && j <= i; ++j) {
            f[i][j] = (f[i][j] + f[i - 1][j - 1]) % mod;
            f[i][j] = (f[i][j] + f[i - j][j]) % mod;
        }
    }
    
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        int sum = 0;
        for (int j = 1; i * j <= n && j <= k; ++j)
            sum = (sum + f[n - i * j][k - j]) % mod;
        ans = (ans + 1LL * sum * qpow(i, m) % mod) % mod;
    }
    
    printf("%d\n", ans);
    
    return 0;
}

おすすめ

転載: www.cnblogs.com/VeniVidiVici/p/11426249.html