1007_Permutation

題目:

hdu_4345_Permutation

 

官方題解:

    循環節的長度爲各獨立置換環長度的最小公倍數。問題即求相加和爲N的正整數的最小公倍數的可能數。
由於1不影響最小公倍數,問題轉化爲相加小於等於N的若干正整數的最小公倍數的可能數。
如果這些正整數包含大於一個質因子,只會使得正整數的和更大。
因而問題再次轉化爲相加小於等於N的若干質數的最小公倍數的可能數。
N<1000,
於是可遞推得,標程用記憶化搜索實現的。

 

個人理解:

       可由N-1得到的最小公倍數,也一定可由N得到,因爲對N-1的任意劃分出的一列數,在這列數中添上一個1後,這列數的最小公倍數都不變。

       於是對於N答案就是N-1的最小公倍數的數目加上N獨有的最小公倍數的數目。

       解題的關鍵在於爲了得到N獨有的最小公倍數,必須把N化爲若干個質數的整數次冪的和,這些冪的最小公倍數就是N獨有的。

       若把N化爲若干個數的和,且其中有合數,那麼使該合數的所有質因數替代該合數,最小公倍數並不變,但數列每項的和卻可能變小,而不可能變大,於是可能產生,N-1也可產生的最小公倍數。

       此後問題變成,有多少種方法把N化成若干質數的整數次冪的和。這個問題的本質和有多少種方法將N化爲若干個正整數的和的本質是一樣的,dp解決。

 

標程:

#include <cstdio>
#include <cstring>

using namespace std;
typedef __int64 ll;
ll f[200][1024];
int p[200], g;

ll calc(int i, int n) {
    if (i == g) return 1;
    if (f[i][n] != -1) return f[i][n];
    f[i][n] = calc(i + 1, n);
    int cnt = p[i];
    while (cnt <= n) {
        f[i][n] += calc(i + 1, n - cnt);
        cnt *= p[i];
    }
    return f[i][n];
}

int main() {
   // freopen("data.in","r",stdin);
   // freopen("data.out","w",stdout);
    int n;
    while (scanf("%d", &n) == 1) {
        int i, j;
        bool u[1024];
        memset(u, 0, sizeof (u));
        for (i = 2; i <= n; i++)
            if (!u[i])
                for (j = i + i; j <= n; j += i)
                    u[j] = true;
        g = 0;
        for (i = 2; i <= n; i++)
            if (!u[i])
                p[g++] = i;
        memset(f, 0XFF, sizeof (f));
        printf("%I64d\n", calc(0, n));
    }
    return 0;
}


發佈了31 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章