zoukankan      html  css  js  c++  java
  • P3768 简单的数学题 (莫比乌斯反演+杜教筛)

    传送门

    题意

    求解((sumlimits^n_{i=1}sumlimits^n_{j=1}ijgcd(i,j))mod~p)

    解题过程

    (sumlimits^n_{i=1}sumlimits^n_{j=1}ijgcd(i,j))

    枚举gcd的值

    (=sumlimits^n_{d=1}dsumlimits^n_{i=1}sumlimits^n_{j=1}ij[gcd(i,j)=d])

    (=sumlimits^n_{d=1}d^3sumlimits^{lfloor frac{n}{d} floor}_{i=1}sumlimits^{lfloor frac{n}{d} floor}_{j=1}ij[gcd(i,j)=1])

    先把后面的部分莫比乌斯反演一下

    (=sumlimits^n_{d=1}d^3sumlimits^{lfloor frac{n}{d} floor}_{i=1}sumlimits^{lfloor frac{n}{d} floor}_{j=1}ijsumlimits_{t|gcd(i,j)}mu(t))

    (t)提前

    (=sumlimits^n_{d=1}d^3sumlimits^{lfloor frac{n}{d} floor}_{t=1}mu(t)*t^2sumlimits^{lfloor frac{n}{td} floor}_{i=1}sumlimits^{lfloor frac{n}{td} floor}_{j=1}ij)

    (1+2+3+cdots+n=S(n))

    那么(=sumlimits^n_{d=1}d^3sumlimits^{lfloor frac{n}{d} floor}_{t=1}mu(t)*t^2sumlimits^{lfloor frac{n}{td} floor}_{i=1}sumlimits^{lfloor frac{n}{td} floor}_{j=1}ij)相当于

    (=sumlimits^n_{d=1}dsumlimits^{lfloor frac{n}{d} floor}_{t=1}mu(t)*t^2d^2S(lfloor frac{n}{td} floor)^2)

    (T=td)

    (=sumlimits^n_{d=1}dsumlimits^{lfloor frac{n}{d} floor}_{t=1}mu(t)*T^2S(lfloor frac{n}{T} floor)^2)

    把T提到最外面

    (=sumlimits_{T=1}^nT^2S(lfloor frac{n}{T} floor)^2sumlimits_{d|T}frac{mu(d)T}{d})

    (sumlimits_{d|n}frac{mu(d)}{d}=frac{varphi(n)}{n})

    (=sumlimits_{T=1}^nT^2S(lfloor frac{n}{T} floor)^2sumlimits_{d|T}frac{mu(d)T}{d}=sumlimits_{T=1}^nT^2S(lfloor frac{n}{T} floor)^2varphi(T))

    好像还是不太行

    我们令(f(i)=i^2varphi(i))

    注意到(sumlimits_{d|n}varphi(d)=n)

    那么设一个(g(i)=i^2)

    那么再看一下杜教筛的套路式子

    (g(1)S(n)=sumlimits_{i=1}^{n}(f*g)(i)-sumlimits_{d=2}^{n}g(d)cdot S(lfloorfrac{n}{d} floor)=sumlimits_{i=1}^{n}i^3-sumlimits_{d=2}^{n}g(d)cdot S(lfloorfrac{n}{d} floor))

    这里的(S)(f)的前缀和,为了方别区分将原来的(1+2+3+cdots+n)称为(Sum(n))

    (S(n)=sumlimits_{i=1}^{n}i^3-sumlimits_{d=2}^{n}d^2cdot S(lfloorfrac{n}{d} floor))

    其实(sumlimits_{i=1}^{n}i^3=Sum(i)^2)

    最后搞出来的是(sumlimits_{T=1}^nSum(lfloor frac{n}{T} floor)^2f(T))

    前半部分能数论分块,后半部分能杜教筛,那么应该差不多了

    代码

    #include <bits/stdc++.h>
    #include <ext/pb_ds/assoc_container.hpp>
    #include <ext/pb_ds/hash_policy.hpp>
    #include <ext/pb_ds/tree_policy.hpp>
    #include <ext/pb_ds/trie_policy.hpp>
    using namespace __gnu_pbds;
    using namespace std;
    // freopen("k.in", "r", stdin);
    // freopen("k.out", "w", stdout);
    // clock_t c1 = clock();
    // std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl;
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    mt19937 rnd(time(NULL));
    #define de(a) cout << #a << " = " << a << endl
    #define rep(i, a, n) for (int i = a; i <= n; i++)
    #define per(i, a, n) for (int i = n; i >= a; i--)
    #define ls ((x) << 1)
    #define rs ((x) << 1 | 1)
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> PII;
    typedef pair<double, double> PDD;
    typedef pair<char, char> PCC;
    typedef pair<ll, ll> PLL;
    typedef vector<int> VI;
    #define inf 0x3f3f3f3f
    const ll INF = 0x3f3f3f3f3f3f3f3f;
    const ll MAXN = 1e7 + 7;
    const ll MAXM = 4e5 + 7;
    const int MOD = 1e9 + 7;
    const double eps = 1e-7;
    ll p, n;
    gp_hash_table<ll, ll> mp;
    int phi[MAXN], pri[MAXN], tot = 0;
    int vis[MAXN];
    ll sum[MAXN];
    void init()
    {
        phi[1] = 1;
        for (int i = 2; i < MAXN; i++)
        {
            if (!vis[i])
                pri[++tot] = i, phi[i] = i - 1;
            for (int j = 1; j <= tot && pri[j] * i < MAXN; j++)
            {
                vis[i * pri[j]] = 1;
                if (i % pri[j] == 0)
                {
                    phi[i * pri[j]] = phi[i] * pri[j];
                    break;
                }
                phi[i * pri[j]] = phi[i] * (pri[j] - 1);
            }
        }
        sum[0] = 0;
        for (int i = 1; i < MAXN; i++)
            sum[i] = (sum[i - 1] + 1LL * phi[i] * i % p * i % p) % p;
    }
    void add(ll &x, ll &y) { x = x + y >= p ? x + y - p : x + y; }
    void del(ll &x, ll &y) { x = x - y < 0 ? x - y + p : x - y; }
    ll Inv(ll a) { return a == 1 ? 1 : (p - p / a) * Inv(p % a) % p; }
    ll inv6;
    ll calSum(ll x)
    {
        x %= p;
        ll temp = x * (x + 1) / 2 % p;
        temp %= p;
        return temp * temp % p;
    }
    ll cal_sumg(ll x)
    {
        x %= p;
        return x * (x << 1 | 1) % p * (x + 1) % p * inv6 % p;
    }
    ll cal_S(ll x)
    {
        if (x < MAXN)
            return sum[x];
        if (mp.find(x) != mp.end())
            return mp[x];
        ll ans = calSum(x);
        for (ll l = 2, r = 0; l <= x; l = r + 1)
        {
            r = x / (x / l);
            ans -= (cal_sumg(r) - cal_sumg(l - 1)) % p * cal_S(x / l) % p;
            ans = ((ans % p) + p) % p;
        }
        return mp[x] = ans;
    }
    int main()
    {
        mp.clear();
        scanf("%lld%lld", &p, &n);
        init();
        inv6 = Inv(6);
        ll ans = 0;
        for (ll l = 1, r = 0; l <= n; l = r + 1)
        {
            r = n / (n / l);
            ll s = calSum(n / l);
            ans += (cal_S(r) - cal_S(l - 1)) % p * s % p;
            ans = ((ans % p) + p) % p;
        }
        printf("%lld
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    redis常用方法
    分享朋友圈、qq等思路及代码
    redis 使用例子
    redis使用实例应用
    js对象与jquery对象介绍
    h5网页跳转到小程序
    redis队列思路介绍
    redis队列思路分析
    php原生方法连接mysql数据库
    mysql 原生语句limit 分页
  • 原文地址:https://www.cnblogs.com/graytido/p/13854954.html
Copyright © 2011-2022 走看看