积性函数 hdu5528 Count a * b

积性函数太有趣了!
做这个题之前,我们需要掌握一些基本知识。

1.若f(x)为积性函数,那么满足f(xy)=f(x)f(y)
2.若f(x)为积性函数, g(x)=d|xf(d) ,那么g(x)也为积性函数
3.学会如何线性处理积性函数。
4.对于积性函数,目标就是学会如何求 f(pq) ,p为质数

回到这个题,我们先考虑求f函数
f(m)=m1a=0m1b=0[gcd(m,ab)!=m]
我们考虑a b的所有组合,一共 m2 情况
考虑f函数的反面,即 f(x)=m1a=0m1b=0[gcd(m,ab)==m]
gcd(m,a)=d ,那么如果满足 gcd(m,ab)=m ,必有 md|b
满足 gcd(m,a)=d 的a个数为 φ(md)
在上面情况满足下且满足 md|b ,b的个数为d
得到 f(m)=m2d|mdφ(d)
能发现前者和后者都是积性函数,拆成2部分记为f1,f2
然后g函数也拆成2部分,记为g1,g2
因为我们知道g1和g2是积性的,所以很容易打表就能找到规律(QAQ太弱了,推不出来,只能打表)
得到
g1(pq)=g1(pq1)p2+1
g2(pq)=(q+1)pq
这题就做完啦

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <memory>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cassert>
#include <climits>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define fuck(x) std::cout << "[" << x << "]";
#define FIN freopen("input.txt", "r", stdin);
#define FOUT freopen("output.txt", "w+", stdout);

typedef long long ll;
typedef long double ldb;
typedef std::pair<ll, int> pli;
typedef std::pair<int, int> pii;
typedef unsigned long long ull;
typedef std::pair<double, double> pdd;

const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int mod = 1e9 + 7;

const int MX = 4e4 + 5;

int prime[MX], psz;
bool not_prime[MX];

void prepare() {
    not_prime[1] = true;
    for(int i = 2; i < MX; i++) {
        if(!not_prime[i]) {
            prime[++psz] = i;
        }
        for(int j = 1; j <= psz && (ll)i * prime[j] < MX; j++) {
            int x = i * prime[j];
            not_prime[x] = true;
            if(i % prime[j] == 0) break;
        }
    }
}
ull solve(int n) {
    ull g1 = 1, g2 = 1;
    for(int i = 1; i <= psz && (ll)prime[i]*prime[i] <= n; i++) {
        if(n % prime[i] == 0) {
            int p = prime[i], q = 0;
            while(n % prime[i] == 0) {
                q++; n /= prime[i];
            }
            ull f1 = 1, f2 = q + 1;
            for(int j = 1; j <= q; j++) {
                f1 = f1 * p * p + 1;
                f2 = f2 * p;
            }
            g1 *= f1; g2 *= f2;
        }
    }
    if(n != 1) {
        int p = n;
        g1 *= (ull)p * p + 1;
        g2 *= 2 * p;
    }
    return g1 - g2;
}
int main() {
    // FIN;
    prepare();
    int T; scanf("%d", &T);
    while(T--) {
        int n; scanf("%d", &n);
        printf("%llu\n", solve(n));
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值