[机房练习赛4.6] mulfunc 线性筛

Problem 5. mulfuc

Input file: mulfuc.in
Output file: mulfunc.out
Time limit: 1 second
Memory limit: 256 MB
Mr. Hu 想让大家了解一下积性函数。
积性是函数的一种重要性态,就像单调性、周期性一样。
一个函数f(n) 如果是积性的,当且仅当:
f(nm) = f(n)f(m) (gcd(m; n) = 1)
如果f(n) 是定义在Z+ 上的积性函数,这样定义Z+ 上的g(n):
g(n) =
Σ
djn
f(d)
那么可以证明g(n) 也是一个积性函数。
而在积性函数中,经常使用到以下几个重要的积性函数(容易证明它们都是积性的):
• (n) 表示正整数n 的正因子个数。
• (n) 表示正整数n 的正因子和。
• (n) 表示正整数n 的Mobius 函数值。
• φ(n) 表示正整数n 的欧拉函数值,即[1; n] 中与n 互质的数的个数。
其中Mobius 函数的定义如下:
(n) =
8><

:
1; n = 1
(��1)r n = p1p2 : : : pr (p1 < p2 < < pr) pi is prime
0 other cases
现在再定义两个函数:
I(n) =
Σ
djn
(d)
E(n) =
Σ
djn
φ(d)
现在Mr. Hu 需要你去求出上面六个函数在1 n 106 范围内的值。
Input
第1 行包含一个整数opt,表示Mr. Hu 需要你求出的函数的标号。对应关系是:
opt 1 2 3 4 5 6
函数 φ I E
Output
输出1 行,包含opt 对应的函数在[1; 106] 范围内的函数值,两个函数值之间用一个空格隔开。
Sample
mulfuc.in mulfunc.out
1 1 2 2 3 2 4 …
mulfuc.in mulfunc.out
2 1 3 4 7 6 12 …
mulfuc.in mulfunc.out
3 1 -1 -1 0 -1 1 …
mulfuc.in mulfunc.out
4 1 1 2 2 4 2 …
Note
上面的样例输出只给出了前面几项,后面用省略号代替了,你需要输出全部的项。
本题满分100 分,分为6 个测试点,每个测试点100/6 分
• 对于第1 个测试点,opt = 1。
• 对于第2 个测试点,opt = 2。
• 对于第3 个测试点,opt = 3。
• 对于第4 个测试点,opt = 4。
• 对于第5 个测试点,opt = 5。
• 对于第6 个测试点,opt = 6。

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

const int N = 1000010;

bool isnot[N];
int pri[N], phi[N], ptot;
long long sum[N];

void init( int n ) {
    isnot[1] = true;
    phi[1] = 1;
    for( int i = 2; i <= n; i++ ) {
        if( !isnot[i] ) {
            pri[ptot++] = i;
            phi[i] = i - 1;
        } 
        for( int t = 0; t < ptot; t++ ){
            int j = pri[t] * i;
            if( j > n ) break;
            isnot[j] = true;
            if( i % pri[t] ) {
                phi[j] = phi[pri[t]] * phi[i];
            } else {
                phi[j] = pri[t] * phi[i];
                break;
            }
        }
    }
    for( int i = 2; i <= n; i++ )
        sum[i] = sum[i-1] + phi[i];
}
int yin[N];
void yinzi( int n ) {
    isnot[1] = true;
    yin[1] = 1;sum[1] = 1;
    for( int i = 2; i <= n; i++ ) {
        if( !isnot[i] ) {
            pri[ptot++] = i;
            yin[i] = 2;sum[i] = i + 1;
        }
        for( int t = 0; t < ptot; t++ ){
            int j = pri[t] * i;
            if( j > n ) break;
            isnot[j] = true;
            if( i % pri[t] == 0 ) {
                int b = i, r = 1, a = pri[t];
                while( b % pri[t] == 0 ) {
                    r++; a *= pri[t]; b /= pri[t];
                }
                yin[j] = (r + 1) * yin[b];
                sum[j] = sum[b];
                while( a % pri[t] == 0 ){
                    sum[j] += sum[b]*a; a /= pri[t];
                }
                break;
            } else {
                yin[j] = yin[pri[t]] * yin[i];
                sum[j] = sum[pri[t]] * sum[i];
            }
        }
    }
}
int mo[N];
void mobius( int n ){
    isnot[1] = true;
    mo[1] = 1;sum[1] = 1;
    for( int i = 2; i <= n; i++ ) {
        if( !isnot[i] ) {
            pri[ptot++] = i;
            mo[i] = -1;
        }
        for( int t = 0; t < ptot; t++ ){
            int j = pri[t] * i;
            if( j > n ) break;
            isnot[j] = true;
            if( i % pri[t] ) {
                mo[j] = mo[i]*mo[pri[t]];
            } else {
                mo[j] = 0;
                break;
            }
        }
    }
    for( int i = 2; i <= n; i++ )
        sum[i] = sum[i-1] + mo[i];
}
int main() {
    freopen("mulfunc.in","r",stdin);
    freopen("mulfunc.out","w",stdout);
    int n;
    scanf("%d", &n);
    if( n == 4 || n == 6 ){
        init(1000000);
        if( n == 4 ){
            for( register int i = 1; i <= 1000000; i++ )
                printf("%d ", phi[i]);
            return 0;
        } if( n == 6 ){
            printf("1 ");
            for( register int i = 2; i <= 1000000; i++ )
                printf("%d ",i);
            return 0;
        }
    }
    if( n == 1 || n == 2 ){
        yinzi(1000000);
        if( n == 1 ){
            for( register int i = 1; i <= 1000000; i++ )
                printf("%d ", yin[i]);
                return 0;
        }else{
            for( register int i = 1; i <= 1000000; i++ )
                printf("%d ", sum[i]);
                return 0;
        }
    }else{
        mobius(1000000);
        if( n == 3 ){
            for( register int i = 1; i <= 1000000; i++ )
                printf("%d ",mo[i]);
            return 0;
        }else{
            printf("1 ");
            for( register int i = 2; i <= 1000000; i++ )
                printf("0 ");
            return 0;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值