loj #6053. 簡單的函數

#6053. 簡單的函數

題目描述

某一天,你發現了一個神奇的函數f(x)f(x)f(x),它知足不少神奇的性質:html

  1. f(1)=1f(1)=1f(1)=1。
  2. f(pc)=p⊕cf(p^c)=p \oplus cf(pc​​)=pc(ppp 爲質數,⊕\oplus⊕ 表示異或)。
  3. 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=1n​​f(i)。ios

因爲這個數比較大,你只須要輸出 ni=1f(i)mod1000000007。ide

輸入格式

一行一個整數 nnn。函數

輸出格式

一行一個整數 ni=1f(i)mod1000000007。ui

樣例

樣例輸入 1

6

樣例輸出 1

16

樣例輸入 2

233333

樣例輸出 2

179004642

樣例輸入3

9876543210

樣例輸出3

895670833

數據範圍與提示

對於30%30\%30%的數據,n≤100n \leq 100n100。
對於60%60\%60%的數據,n≤106n \leq 10^6n106​​。
對於100%100\%100%的數據,1≤n≤10101 \leq n \leq 10^{10}1n1010​​。
atom

 

#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;
}
40分 暴力
相關文章
相關標籤/搜索