loj #6053. 简单的函数
#6053. 简单的函数
题目描述
某一天,你发现了一个神奇的函数f(x)f(x)f(x),它满足很多神奇的性质:
- f(1)=1f(1)=1f(1)=1。
- f(pc)=p⊕cf(p^c)=p \oplus cf(pc)=p⊕c(ppp 为质数,⊕\oplus⊕ 表示异或)。
- f(ab)=f(a)f(b)f(ab)=f(a)f(b)f(ab)=f(a)f(b)(aaa 与 bbb 互质)。
你看到这个函数之后十分高兴,于是就想要求出 ∑i=1nf(i)\sum\limits_{i=1}^n f(i)i=1∑nf(i)。
由于这个数比较大,你只需要输出 n∑i=1f(i)mod1000000007。
输入格式
一行一个整数 nnn。
输出格式
一行一个整数 n∑i=1f(i)mod1000000007。
样例
样例输入 1
6
样例输出 1
16
样例输入 2
233333
样例输出 2
179004642
样例输入3
9876543210
样例输出3
895670833
数据范围与提示
对于30%30\%30%的数据,n≤100n \leq 100n≤100。
对于60%60\%60%的数据,n≤106n \leq 10^6n≤106。
对于100%100\%100%的数据,1≤n≤10101 \leq n \leq 10^{10}1≤n≤1010。
#include<iostream> #include<cstdio> #include<cstring> #define maxn 1000010 #define mod 1000000007 using namespace std; int p[maxn],cnt,n,f[maxn]; bool vis[maxn]; void prepare(){ for(int i=2;i<=n;i++){ if(!vis[i])p[++cnt]=i; for(int j=1;j<=cnt&&i*p[j]<=n;j++){ vis[i*p[j]]=1; if(i%p[j]==0)break; } } } void make(int x){ int a=1,b=1,now=x; for(int i=1;i<=cnt;i++){ if(now==1)break; if(now%p[i]==0){ if(a==1) while(now%p[i]==0)a*=p[i],now/=p[i]; else while(now%p[i]==0)b*=p[i],now/=p[i]; } } f[x]=f[a]*f[b]; } int main(){ scanf("%d",&n);prepare(); memset(f,-1,sizeof(f)); f[1]=1; for(int i=1;i<=cnt;i++){ int t=0;long long mul=1; while(1){ t++; mul=mul*(long long)p[i]; if(mul>1LL*n)break; else f[mul]=p[i]^t; } } int ans=0; for(int i=1;i<=n;i++){ if(f[i]==-1)make(i); ans+=f[i]; if(ans>=mod)ans-=mod; } printf("%d\n",ans); return 0; }