题解 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;
}
以后考虑子集来枚举答案先考虑递推。
注意循环变量中的溢出。