Product(2019年西安邀请赛B+杜教筛)

博客介绍了2019年西安邀请赛B题的解题思路,主要涉及数论和算法。首先对题目公式进行化简,然后将指数部分拆解为关于gcd(i,j)的求和。博主详细阐述了如何利用数论分块和杜教筛方法求解d的因子个数(df(d))以及i=1∑⌊dn⌋ϕ(i)。最后给出了代码实现。" 99289440,8547035,CentOS7防火墙配置完全指南,"['防火墙', 'CentOS7', 'Linux', '系统管理']
摘要由CSDN通过智能技术生成

题目链接

传送门

题面

在这里插入图片描述
在这里插入图片描述

思路:

我们先将公式进行化简:
∏ i = 1 n ∏ i = 1 n ∏ i = 1 n m g c d ( i , j ) [ k ∣ g c d ( i , j ) ] = m ∑ i = 1 n ∑ j = 1 n ∑ k = 1 n g c d ( i , j ) [ k ∣ g c d ( i , j ) ] \begin{aligned} &\prod_{i=1}^{n}\prod_{i=1}^{n}\prod_{i=1}^{n}m^{gcd(i,j)[k|gcd(i,j)]}&\\ =&m^{\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{n}gcd(i,j)[k|gcd(i,j)]}& \end{aligned} =i=1ni=1ni=1nmgcd(i,j)[kgcd(i,j)]mi=1nj=1nk=1ngcd(i,j)[kgcd(i,j)]
现在我们单独考虑指数部分:
∑ i = 1 n ∑ j = 1 n ∑ k = 1 n g c d ( i , j ) [ k ∣ g c d ( i , j ) ] = ∑ d = 1 n d f ( d ) ∑ i = 1 n ∑ k = 1 n [ g c d ( i , j ) = d ] = ∑ d = 1 n d f ( d ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ [ g c d ( i , j ) = 1 ] = ∑ d = 1 n d f ( d ) ( 2 ∑ i = 1 ⌊ n d ⌋ ϕ ( i ) − 1 ) = 2 ∑ d = 1 n d f ( d ) ∑ i = 1 ⌊ n d ⌋ ϕ ( i ) − ∑ d = 1 n d f ( d ) , 其中 f ( d ) 为 d 的 因 子 个 数 \begin{aligned} &\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{n}gcd(i,j)[k|gcd(i,j)]&\\ =&\sum\limits_{d=1}^{n}df(d)\sum\limits_{i=1}^{n}\sum\limits_{k=1}^{n}[gcd(i,j)=d]&\\ =&\sum\limits_{d=1}^{n}df(d)\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{n}{d}\rfloor}[gcd(i,j)=1]&\\ =&\sum\limits_{d=1}^{n}df(d)(2\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\phi(i)-1)&\\ =&2\sum\limits_{d=1}^{n}df(d)\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\phi(i)-\sum\limits_{d=1}^{n}df(d),\text{其中}f(d)\text{为}d\text{}的因子个数& \end{aligned} ====i=1nj=1nk=1ngcd(i,j)[kgcd(i,j)]d=1ndf(d)i=1nk=1n[gcd(i,j)=d]d=1ndf(d)i=1dnj=1dn[gcd(i,j)=1]d=1ndf(d)(2i=1dnϕ(i)1)2d=1ndf(d)i=1dnϕ(i)d=1ndf(d),其中f(d)d
对于 ∑ d = 1 n d f ( d ) \sum\limits_{d=1}^{n}df(d) d=1ndf(d)我们发现可以进行如下化简求解:
∑ i = 1 n i f ( i ) = ∑ i = 1 n i ∑ j ∣ i 1 = ∑ j = 1 n ∑ j ∣ i i = ∑ j = 1 n j × ( 1 + ⌊ n j ⌋ ) ⌊ n j ⌋ 2 \begin{aligned} &\sum\limits_{i=1}^{n}if(i)&\\ =&\sum\limits_{i=1}^{n}i\sum\limits_{j|i}1&\\ =&\sum\limits_{j=1}^{n}\sum_{j|i}i&\\ =&\sum\limits_{j=1}^{n}\frac{j\times(1+\lfloor\frac{n}{j}\rfloor)\lfloor\frac{n}{j}\rfloor}{2}&\\ \end{aligned} ===i=1nif(i)i=1niji1j=1njiij=1n2j×(1+jn)jn
对于 ∑ d = 1 n d f ( d ) \sum\limits_{d=1}^{n}df(d) d=1ndf(d)我们可以直接通过数论分块来求,对于 ∑ d = 1 n d f ( d ) ∑ i = 1 ⌊ n d ⌋ ϕ ( i ) \sum\limits_{d=1}^{n}df(d)\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\phi(i) d=1ndf(d)i=1dnϕ(i)我们可以对 ∑ i = 1 ⌊ n d ⌋ ϕ ( i ) \sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\phi(i) i=1dnϕ(i)进行数论分块用杜教筛求出来,然后在同一块中对 ∑ d = 1 n d f ( d ) \sum\limits_{d=1}^{n}df(d) d=1ndf(d)进行数论分块求出来。

代码实现如下

#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;

typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;

#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("D://code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)

const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 5e6 + 3;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;

bool v[maxn];
int n, m, p, cnt, MOD;
int isp[maxn/10], phi[maxn];
int sum[maxn], ssum[maxn];
unordered_map<int, int> dp1, dp2;

int add(int x, int y) {
    if(y < 0) x += y;
    else x = x - MOD + y;
    if(x < 0) x += MOD;
    return x;
}

void init() {
    phi[1] = ssum[1] = 1;
    for(int i = 2; i < maxn; ++i) {
        if(!v[i]) {
            ssum[i] = 2;
            phi[i] = i - 1;
            isp[cnt++] = i;
        }
        for(int j = 0; j < cnt && i * isp[j] < maxn; ++j) {
            v[i*isp[j]] = 1;
            if(i % isp[j] == 0) {
                phi[i*isp[j]] = phi[i] * isp[j];
                int pp = 1, x = i;
                while(x % isp[j] == 0) x /= isp[j], pp++;
                ssum[i*isp[j]] = ssum[i] / pp * (pp + 1);
                break;
            }
            phi[i*isp[j]] = phi[i] * (isp[j] - 1);
            ssum[i*isp[j]] = ssum[i] * 2;
        }
    }
    for(int i = 1; i < maxn; ++i) {
        sum[i] = add(sum[i-1], phi[i]);
        ssum[i] = add(1LL * ssum[i] * i % MOD, ssum[i-1]);
    }
}

int getphi(int x) {
    if(x < maxn) return sum[x];
    if(dp1[x]) return dp1[x];
    int ans = (1LL * x * (x + 1) / 2) % MOD;
    for(int l = 2, r; l <= x; l = r + 1) {
        r = x / (x / l);
        int tmp = 1LL * (r - l + 1) * getphi(x/l) % MOD;
        ans = add(ans, -tmp);
    }
    return dp1[x] = ans;
}

int qpow(int x, int n) {
    int res = 1;
    while(n) {
        if(n & 1) res = 1LL * res * x % p;
        x = 1LL * x * x % p;
        n >>= 1;
    }
    return res;
}

int getnum(int x) {
    if(x < maxn) return ssum[x];
    if(dp2[x]) return dp2[x];
    int ans = 0;
    for(int l = 1, r; l <= x; l = r + 1) {
        r = x / (x / l);
        LL tmp1 = 1LL * ((x / l) + 1) * (x / l);
        LL tmp2 = 1LL * (l + r) * (r - l + 1) / 2;
        ans = add(ans, tmp1 * tmp2 / 2 % MOD);
    }
    return dp2[x] = ans;
}

int main(){
    scanf("%d%d%d", &n, &m, &p);
    MOD = p - 1;
    init();
    int ans2 = getnum(n);
    int ans1 = 0;
    for(int l = 1, r; l <= n; l = r + 1) {
        r = n / (n / l);
        int tmp1 = getphi(n / l);
        int tmp2 = add(getnum(r), -getnum(l-1));
        ans1 = add(ans1, 1LL * tmp1 * tmp2 % MOD);
    }
    ans1 = 2LL * ans1 % MOD;
    int ans = add(ans1, -ans2);
    printf("%d\n", qpow(m, ans));
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值