@hdu - 6607 @簡単に数学の問題


@説明@

求:
\ [\ sum_ {i = 1} ^ {N} \ sum_ {J = 1} ^ {n}はGCD ^ K(i、j)は\回LCM(I、J)\回[GCD(I、J )\ \のmod 10 ^ 9 + 7]プライムで\]

元のタイトルポータル。

@解決@

\ [\ {整列}開始ANS&= \ sum_ {i = 1} ^ {N} \ sum_ {J = 1} ^ {n}はGCD ^ K(i、j)は\回LCM(I、J)\回[GCD(I、J)\素数で】\\&= \ sum_ {D = 1} ^ {N} [プライムにおけるD \] \回{K + 1} \ sum_ {I = 1} ^ {^ D \ lfloor \ FRAC {n}は{D} \ rfloor} \ sum_ {J = 1} ^ {\ lfloor \ FRAC {n}は{D} \ rfloor} [GCD(I、J)= 1] \回I \回J \端{整列} \]

その背景には、古典的な問題です。明らかメビウス反転することができるが、しかし、私は、J同じ範囲はオイラー関数を使用することができることに留意。

結論ベース\(GCD(I、N)= GCD(N - )\ I、N) 及び素数nは常にペアで存在するが、そうある:
\ [\ sum_ {I} = ^ {n}は1。 \ sum_ {J = 1} ^ {N} [GCD(I、J)= 1] \回I \回J = \ sum_ ^ {n}は{I 1 =} \ PHI(I)\ iは^ 2回\ ]

\(S(N)= \ sum_ {私は= 1} ^ {N-} \ファイ(I)\タイムズI ^ 2 \) デュの教示ふるい要求することができる\(S \)は(MIN-25することができない篩)しないでください。その後:

\ [ANS = \ sum_ {D = 1} ^ {n}は素数で[D \] \回{K + 1} \回S(\ lfloor \ FRAC {n}は{D} \ rfloor)^ D \]

場合(S(\ lfloor \ FRAC \ {n}は{D} \ rfloor)\) ブロック、我々は素数K + 1とプレフィックスの力を要求します。ミン-25は、実際に画面の最初の半分です。

@acceptedコード@

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

typedef long long ll;

const int MOD = int(1E9) + 7;
const int MAXN = 4650000;

inline int add(int x, int y) {return (x + y >= MOD ? x + y - MOD : x + y);}
inline int sub(int x, int y) {return (x - y < 0 ? x - y + MOD : x - y);}
inline int mul(int x, int y) {return 1LL * x * y % MOD;}

int pow_mod(int b, int p) {
    int ret = 1;
    for(int i=p;i;i>>=1,b=mul(b,b))
        if( i & 1 ) ret = mul(ret, b);
    return ret;
}

bool nprm[MAXN + 5];
int prm[MAXN + 5], phi[MAXN + 5], pcnt;
void sieve() {
    phi[1] = 1;
    for(int i=2;i<=MAXN;i++) {
        if( !nprm[i] ) prm[++pcnt] = i, phi[i] = i - 1;
        for(int j=1;i*prm[j]<=MAXN;j++) {
            nprm[i*prm[j]] = true;
            if( i % prm[j] == 0 ) {
                phi[i*prm[j]] = phi[i]*prm[j];
                break;
            }
            else phi[i*prm[j]] = phi[i]*phi[prm[j]];
        }
    }
}
int c[105][105], f[105][105];
void get_coef() {
    for(int i=0;i<=102;i++) {
        c[i][0] = 1;
        for(int j=1;j<=i;j++)
            c[i][j] = add(c[i-1][j], c[i-1][j-1]);
    }
    for(int i=0;i<=101;i++) {
        for(int j=0;j<=i+1;j++)
            f[i][j] = c[i+1][j];
        for(int j=0;j<i;j++) {
            for(int k=0;k<=j+1;k++)
                f[i][k] = sub(f[i][k], mul(c[i+1][j], f[j][k]));
        }
        int iv = pow_mod(i + 1, MOD - 2);
        for(int j=0;j<=i+1;j++)
            f[i][j] = mul(f[i][j], iv);
    }
}
int get_sum(int n, int k) {
    int ret = 0;
    for(int i=k+1;i>=0;i--)
        ret = add(mul(ret, n), f[k][i]);
    return ret;
}
int sum[MAXN + 5];
void init() {
    sieve(), get_coef();
    for(int i=1;i<=MAXN;i++)
        sum[i] = add(sum[i-1], mul(mul(i, i), phi[i]));
}
ll n; int k;
int id1[MAXN + 5], id2[MAXN + 5], cnt;
int id(ll m) {return (m <= MAXN ? id1[m] : id2[n/m]);}
ll a[MAXN + 5]; int s[MAXN + 5];
void get_id() {
    cnt = 0;
    for(ll i=1;i<=n;i=(n/(n/i))+1) {
        ll p = n / i;
        if( p <= MAXN ) id1[p] = (++cnt);
        else id2[n/p] = (++cnt);
        a[cnt] = p, s[cnt] = -1;
    }
}
int phisum(ll m) {
    if( m <= MAXN ) return sum[m];
    int &ans = s[id(m)];
    if( ans != -1 ) return ans;
    ans = get_sum(m % MOD, 3);
    for(ll i=2;i<=m;i++) {
        ll p = m / i, j = m / p;
        ans = sub(ans, mul(sub(get_sum(j % MOD, 2), get_sum((i-1) % MOD, 2)), phisum(p)));
        i = j;
    }
    return ans;
}
int dp[MAXN + 5];
void get_dp() {
    for(int i=1;i<=cnt;i++) dp[i] = sub(get_sum(a[i] % MOD, k + 1), 1);
    int tmp = 0;
    for(int i=1;i<=pcnt;i++) {
        ll sq = 1LL*prm[i]*prm[i]; int del = pow_mod(prm[i], k + 1);
        if( sq > n ) break;
        for(int j=1;j<=cnt;j++) {
            if( sq > a[j] ) break;
            dp[j] = sub(dp[j], mul(del, sub(dp[id(a[j] / prm[i])], tmp)));
        }
        tmp = add(tmp, del);
    }
}
void solve() {
    scanf("%lld%d", &n, &k), get_id(), get_dp();
    
    int ans = 0;
    for(ll i=1;i<=n;i++) {
        ll p = n / i, j = n / p;
        ans = add(ans, mul(sub(phisum(j), phisum(i - 1)), dp[id(p)]));
        i = j;
    }
    printf("%d\n", ans);
}
int main() {
    init();
    int T; scanf("%d", &T);
    while( T-- ) solve();
}

詳細@

すべての数値は、長い長いブロックを取ら割り切れるである必要がありますが、モジュロint型に変身します。パンに注意を払っていません。

おすすめ

転載: www.cnblogs.com/Tiw-Air-OAO/p/12500313.html