HDU6706 CCPC 2019网络赛 huntian oy 推式子+杜教筛

Posted danzh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU6706 CCPC 2019网络赛 huntian oy 推式子+杜教筛相关的知识,希望对你有一定的参考价值。

CCPC 2019 网络赛 HDU 6706 huntian oy

标签

  • 奇奇怪怪的数论结论
  • 杜教筛

前言

简明题意

  • 给定n,a,b,求:
    \\[\\sum_i=1^n\\sum_j=1^igcd(i^a-j^a,i^b-j^b)[gcd(i,j)=1]\\%(10^9+7)\\]

思路

  • 首先有一个结论:
    \\[gcd(i^a-j^a,i^b-j^b)=i^gcd(a,b)-j^gcd(a,b)\\]
  • 上面的结论对于i,j互质是成立的。关注这题,条件式里就有[gcd(i,j)=1],所以我们可以直接替换:(由于ab互质,所以指数直接去掉)
    \\[\\sum_i=1^n\\sum_j=1^i(i-j)[gcd(i,j)=1]\\]
  • (其实我比赛的时候猜出来gcd那一坨就等于i-j,然后我写了个暴力验证一下,发现有些数不相等,当时情急,就没往这方面想了,好难过)
  • 推到这里,就太简单了。接下来我们我们把减法分离开:
    \\[\\sum_i=1^n\\sum_j=1^ii[gcd(i,j)=1]-\\sum_i=1^n\\sum_j=1^ij[gcd(i,j)=1]\\]
  • 然后分别求一下这两个式子。第一个式子比较好求,重点是第二个式子。
    \\[\\sum_i=1^n\\sum_j=1^ij[gcd(i,j)=1]=\\frac 12\\sum_i=1^ni\\phi(i)+\\frac[n>=1]2\\]

    这个式子的推导过程放在我的博客《数论公式总结》里面了

  • 所以原式就等于
    \\[\\sum_i=1^ni\\phi(i)-\\frac 12\\sum_i=1^ni\\phi(i)+\\frac[n>=1]2=\\frac 12\\left(\\sum_i=1^ni\\phi(i)-1\\right)\\]
  • 好了,n<=1e9,暴力去算和式会超时。这里杜教筛。
  • \\(f(n)=n\\phi(n)\\)\\(S(n)=\\sum\\limits_i=1^nf(i)\\)。我们杜教筛,构造g:
    \\[S(n)g(1)=\\sum_i=1^n(f*g)(i)-\\sum_i=2^ng(i)S(\\frac ni)\\]
  • 现在难点就在于怎么找g函数。找g函数,我们一般先把狄利克雷展开:
    \\[f*g=\\sum_d|nd\\phi(d)*g(\\frac nd)\\]
  • 所以很显然了,我们取g=id,卷积就是: \\[f*g=\\sum_d|nn\\phi(d)=n\\sum_d|n\\phi(d)\\]
  • \\(\\sum\\limits_d|n\\phi(d)=n\\)(这个相当于\\(\\phi*I=id\\),用卷积很好证明),所以:
    \\[(f*g)(n)=\\sum_d|nn\\phi(d)=n^2\\]
  • 所以杜教筛的式子:
    \\[S(n)=\\sum_i=1^ni^2-\\sum_i=2^niS(\\frac ni)\\]
  • 然后就能很轻松地杜教筛啦~然而T了...
  • 上面的式子如果需要求积性函数的前缀和,那么大家肯定会写一个线性筛。而这里没有,是不是就代表不需要预处理呢?其实还是需要的,要预处理出\\(f(n)=n\\phi(n)\\)的前缀和,才能降低杜教筛的复杂度。

注意事项

  • 注意溢出问题

总结

  • 杜教筛在分块的那一部分有减法操作,记得那里的减法操作不要写-=,因为那里的减法也要取模...

AC代码

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

const int maxn = 5e6 + 10;
const int mod = 1e9 + 7;

int ksm(int a, int b)

    int ans = 1, base = a;
    while (b)
    
        if (b & 1)
            ans = 1ll * ans * base % mod;
        b >>= 1;
        base = 1ll * base * base % mod;
    
    return ans;


int inv6, inv2;

int prime[maxn], phi[maxn], pre[maxn];
bool no_prime[maxn];
int shai(int n)

    int cnt = 0;
    no_prime[1] = phi[1] = 1;

    for (int i = 2; i <= n; i++)
    
        if (!no_prime[i])
            prime[++cnt] = i, phi[i] = i - 1;

        for (int j = 1; j <= cnt && i * prime[j] <= n; j++)
        
            no_prime[prime[j] * i] = 1;
            phi[prime[j] * i] = i % prime[j] == 0 ? phi[i] * prime[j] : phi[i] * (prime[j] - 1);
            if (i % prime[j] == 0) break;
        
    

    for (int i = 1; i <= n; i++)
        pre[i] = (1ll * pre[i - 1] + 1ll * i * phi[i] % mod) % mod;

    return cnt;


unordered_map<int, int> rec;
int S(int n)

    if (n <= maxn - 10) return pre[n];
    if (rec[n]) return rec[n];
    long long ans = 1ll * n * (n + 1) % mod * (2 * n + 1) % mod * inv6 % mod;
    int l = 2, r = n;
    while (l <= n)
    
        r = n / (n / l);
        ans = ((ans - 1ll * (l + r) * (r - l + 1) % mod * inv2 % mod * S(n / l) % mod) % mod + mod) % mod;
        l = r + 1;
    
    return rec[n] = ans;


void solve()

    inv6 = ksm(6, mod - 2);
    inv2 = ksm(2, mod - 2);

    shai(maxn - 10);

    int t;
    scanf("%d", &t);
    while (t--)
    
        int n, a, b;
        scanf("%d%d%d", &n, &a, &b);
        printf("%lld\\n", 1ll * (S(n) - 1 + mod) % mod * inv2 % mod);
    


int main()

    solve();
    return 0;

以上是关于HDU6706 CCPC 2019网络赛 huntian oy 推式子+杜教筛的主要内容,如果未能解决你的问题,请参考以下文章

2019CCPC网络赛 HDU 6702——找规律

CCPC 2019 网络赛 1002 array (权值线段树)

2017 ccpc 网络赛 hdu 6156

hdu6153 A Secret CCPC网络赛 51nod 1277 KMP

HDU 6438 Buy and Resell (CCPC网络赛) 堆 贪心

hdu 6152 : Friend-Graph (2017 CCPC网络赛 1003)