Loading

题解 P3412

题解 P3512 ,狄利克雷卷积:

链接

这个题复杂度分析有些失误,所以做得不快,实际上非常简单:

推完式子后得到:

\[\sum\limits_{k|n}\phi(k)\frac nk \]

其实到这里就可以做了,因为 \(10^9\) 以内因子个数最多的数的因子个数不会很大。上图:

这里介绍另一种方法,我们把 \(\phi(k)\) 展开,可以得到:

\[n(\sum\limits_{k|n}\prod\limits_{i=1}^{m_k}\frac{p_i-1}{p_i}) \]

不难发现,后者括号里和式中有一些项是相同的。

\(n=\prod_{i=1}^mp_i^{\alpha_i}\)

显然,\(\prod_{i=1}^{q} \frac{p_i-1}{p_i}\) 的个数为 \(\prod_{i=1}^q\alpha _i\) ,我们利用这个事情。

因为每一个因子的贡献是独立的,所以这个东西可以递推。设:

\[f_i=\frac{p_i-1}{p_i},b_i=f_i\times \alpha _i \]

那么我们的答案应该是:

\[b_1+b_2+...+b_1b_2+b_1b_3+...b_1b_2b_3... \]

那么这个数是多少呢?考虑前 \(i\)\(b\) 的答案我们已经有了,为 \(ans_i\) ,那么不难发现:

\[ans_{i+1}=ans_i(b_{i+1}+1) \]

也就是考虑第 \(b_{i+1}\) 选不选。

也可以这样理解,我们实际上是枚举质因数的一个子集,所以上面的方法是显然正确的。

代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N number
#define M number
using namespace std;

const int INF=0x3f3f3f3f;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

ll n;

inline ull get_fac(ll n){
    ull ans=n;
    for(ll i=2;i*i<=n;i++){
        ll cnt=0;
        while(n%i==0){
            n/=i;cnt++;
        }
        ans=ans/i*(i-1)*cnt+ans;
    }
    if(n>1){ans=ans/n*(n-1)+ans;}
    return ans;
}

int main(){
    read(n);
    ull ans=get_fac(n);
    printf("%llu",ans);
    return 0;
}

以后考虑子集来枚举答案先考虑递推。

注意循环变量中的溢出。

posted @ 2021-07-02 09:22  hyl天梦  阅读(67)  评论(0编辑  收藏  举报