HDU 4944 FSF’s game(計數遊戲)

bigbigship發表於2014-11-22

題目連結:

http://acm.hdu.edu.cn/showproblem.php?pid=4944

題意:

給定一個長度n, 用長度為 a,b 的邊組成一個矩形 (1<=a<=b<=n) 我們可以將其組成n(n+1)/2個不同的矩形,

對於每一個矩形 我們可以得到一個val  val=sigma(a*b/gcd(a/k,b/k)) 其中k為a,b的公因子,求這個val;


分析:

我們定義一個函式calu(i,j)   calu(i,j)的意思是sigma{(i*j/gcd(i/k,j/k))},

則ans=sigma {calu(i,j)}(1<=i<=j<=n);

我們設dp[n]表示最大的邊長為n的邊所得到的val,

那麼dp[n]=dp[n-1]+sigma{ calu(i,n) }(1<=i<=n)

然後我們需要解決的問題就是求sigma{ calu(i,n) }(1<=i<=n);

我們先討論calu(i,n)=n*(i/c1+i/c2+...),其中cj為n和i的最大公約數d的所有因子。

那麼我們可以列舉所有n的因子j,對於因子j,存在這個因子且小於等於n的數字中有j,2*j,3*j,...,n。

我們可以得到s[j]=(1+2+3+...n/j)*n=(n/j+1)*(n/j)/2*n。

那麼val[n]=sigma{fun(i,n)}(1<=i<=n)=sigma{s[j]} (j為n的因子)。


程式碼如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

typedef long long LL;

const LL mod = (LL)1<<32;
const int maxn = 500010;

LL cnt[maxn],dp[maxn];

void init()
{
    memset(cnt,0,sizeof(cnt));
    for(LL i=1;i<maxn;i++){//列舉因子
        for(LL j=i;j<maxn;j+=i)//統計因子的個數的和
            cnt[j]+=(j/i+1)*(j/i)/2;
    }
}

void solve()
{
    dp[1]=1;
    for(int i=2;i<maxn;i++){
        dp[i]=(dp[i-1]+i*cnt[i])%mod;
    }
}
int main()
{
    int t,n,cas=1;
    init();
    solve();
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        printf("Case #%d: %I64d\n",cas++,dp[n]);
    }
    return 0;
}



相關文章