SCUT - 354 - CC的简单多项式 - 杜教筛

https://scut.online/p/354
跟多项式一点关系都没有。
注意到其实两个多项式在1处求值,那么就是他们的系数加起来。

列一列发现系数就是n以内两两求gcd的值,还自动把0去掉了。

那么就是
\(\sum\limits_{i=1}^{n}\sum\limits_{i=1}^{n}gcd(i^2,j^2)\)

这种情况就要枚举g但是为了方便我们也是枚举g而不是g平方
\(\sum\limits_{g=1}^{n}g^2\sum\limits_{i=1}^{n}\sum\limits_{i=1}^{n}[gcd(i^2,j^2)==g^2]\)

列一列gcd的分解式发现其实可以把平方约分掉
\(\sum\limits_{g=1}^{n}g^2\sum\limits_{i=1}^{n}\sum\limits_{i=1}^{n}[gcd(i,j)==g]\)

二话不说除以g
\(\sum\limits_{g=1}^{n}g^2\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}[gcd(i,j)==1]\)

套上反演
\(\sum\limits_{g=1}^{n}g^2\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}\sum\limits_{k|gcd(i,j)}\mu(k)\)
\(\sum\limits_{g=1}^{n}g^2\sum\limits_{k=1}^{n}\mu(k){\lfloor\frac{n}{gk}\rfloor}^{2}\)

枚举T
\(\sum\limits_{T=1}^{n}{\lfloor\frac{n}{T}\rfloor}^{2}\sum\limits_{g|T}g^2\mu(\frac{T}{g})\)

假如搞得出后面那个狄利克雷卷积的前缀和,那么可以分块回答,看看复杂度刚刚够的样子。

后面那个是
\(\sum\limits_{g|T}g^2\mu(\frac{T}{g})\)

也就是
\(id^2*\mu\)

嗷神提示卷一个东西,恒等函数\(I(n)=1\)
\((id^2*\mu)*I\)

结合律
\(id^2*(\mu*I)\)

后面那个就是
\(id^2*(\epsilon)\)

这个东西展开就是
\(\sum\limits_{g|T}g^2[\frac{T}{g}==1]\)
\(T^2\)

也就是说卷积之后的前缀和是\(s_2\),而恒等函数的前缀和就是\(s_0\)

上一波杜教筛就可以了

测试发现unorder_map和cc_hash_table差异非常小。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

inline ll read() {
    ll x = 0;
    //int f = 0;
    char c;
    do {
        c = getchar();
        /*if(c == '-')
            f = 1;*/
    } while(c < '0' || c > '9');
    do {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    } while(c >= '0' && c <= '9');
    //return f ? -x : x;
    return x;
}

inline void _write(int x) {
    if(x > 9)
        _write(x / 10);
    putchar(x % 10 + '0');
}

inline void write(int x) {
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    _write(x);
    putchar('\n');
}

/*void TestCase(int ti);

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
    //freopen("Yinku.out","w",stdout);
#endif // Yinku
    int T = 1;
    for(int ti = 1; ti <= T; ti++)
        TestCase(ti);
}*/

/*---  ---*/

const int mod = 998244353;
const int inv2 = (mod + 1) >> 1;
const int MAXN = 1.5e7;

int pri[MAXN + 1];
int &pritop = pri[0];
int f[MAXN + 1];
int pk[MAXN + 1];

void sieve(int n = MAXN) {
    pk[1] = 1;
    f[1] = 1;
    for(int i = 2; i <= n; i++) {
        if(!pri[i]) {
            pri[++pritop] = i;
            pk[i] = i;
            f[i] = (1ll * i * i - 1ll) % mod;
        }
        for(int j = 1; j <= pritop; j++) {
            int &p = pri[j];
            int t = i * p;
            if(t > n)
                break;
            pri[t] = 1;
            if(i % p) {
                pk[t] = p;
                f[t] = 1ll * f[i] * f[p] % mod;
            } else {
                pk[t] = pk[i] * p;
                if(pk[t] == t) {
                    f[t] = 1ll * f[i] * p % mod * p % mod;
                } else {
                    f[t] = 1ll * f[t / pk[t]] * f[pk[t]] % mod;
                }
                break;
            }
        }
    }
    for(int i = 1; i <= n; i++) {
        f[i] = f[i - 1] + f[i];
        if(f[i] >= mod)
            f[i] -= mod;
    }
}

/*inline int qpow(ll x, int n) {
    ll res = 1;
    while(n) {
        if(n & 1) {
            res *= x;
            if(res >= mod)
                res %= mod;
        }
        x *= x;
        if(x >= mod)
            x %= mod;
        n >>= 1;
    }
    return res;
}*/

const int inv6 = 166374059; //qpow(6, mod - 2);

inline int s2(ll n) {
    if(n >= mod)
        n %= mod;
    ll tmp = n * (n + 1);
    if(tmp >= mod)
        tmp %= mod;
    tmp *= n * 2 + 1 ;
    if(tmp >= mod)
        tmp %= mod;
    tmp *= inv6;
    if(tmp >= mod)
        tmp %= mod;
    return tmp;
}

unordered_map<ll, int> Sf;

inline int F(ll n) {
    if(n <= MAXN)
        return f[n];
    if(Sf.count(n))
        return Sf[n];
    ll ret = s2(n);
    for(ll l = 2, r; l <= n; l = r + 1) {
        ll t = n / l;
        r = n / t;
        ret -= (r - l + 1) % mod * F(t) % mod;
        if(ret < 0)
            ret += mod;
    }
    return Sf[n] = ret;
}

inline int S(ll n) {
    ll res = 0;
    for(ll l = 1, r; l <= n; l = r + 1) {
        ll t = n / l;
        r = n / t;
        ll tmp = F(r) - F(l - 1);
        if(tmp < 0)
            tmp += mod;
        if(t >= mod)
            t %= mod;
        t *= t;
        if(t >= mod)
            t %= mod;
        tmp *= t;
        if(tmp >= mod)
            tmp %= mod;
        res += tmp;
        if(res >= mod)
            res -= mod;
    }
    return res;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
    //freopen("Yinku.out","w",stdout);
#endif // Yinku
    sieve();
    int T = read();
    while(T--) {
        write(S(read()));
    }
}

但是好像发现一个问题,别人都是欧拉函数的?
\(\sum\limits_{g=1}^{n}g^2\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}[gcd(i,j)==1]\)

这里内部记为
\(S(n)=\sum\limits_{i=1}^{n}\sum\limits_{i=1}^{n}[gcd(i,j)==1]\)

n以内互质对的个数?那么枚举较大的那个,小的那个要和他互质,就是欧拉函数,大小互换多了一倍,其中(1,1)重复去掉一个
\(S(n)=-1+2\sum\limits_{i=1}^{n}\varphi(i)\)

所以原式就是
\(\sum\limits_{g=1}^{n}g^2S(\lfloor\frac{n}{g}\rfloor)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

inline ll read() {
    ll x = 0;
    //int f = 0;
    char c;
    do {
        c = getchar();
        /*if(c == '-')
            f = 1;*/
    } while(c < '0' || c > '9');
    do {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    } while(c >= '0' && c <= '9');
    //return f ? -x : x;
    return x;
}

inline void _write(int x) {
    if(x > 9)
        _write(x / 10);
    putchar(x % 10 + '0');
}

inline void write(int x) {
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    _write(x);
    putchar('\n');
}

/*void TestCase(int ti);

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
    //freopen("Yinku.out","w",stdout);
#endif // Yinku
    int T = 1;
    for(int ti = 1; ti <= T; ti++)
        TestCase(ti);
}*/

/*---  ---*/

const int mod = 998244353;
const int inv2 = (mod + 1) >> 1;
const int MAXN = 1.6e7;

int pri[MAXN + 1];
int &pritop = pri[0];
int phi[MAXN + 1];

void sieve(int n = MAXN) {
    phi[1] = 1;
    for(int i = 2; i <= n; i++) {
        if(!pri[i]) {
            pri[++pritop] = i;
            phi[i] = i - 1;
        }
        for(int j = 1; j <= pritop; j++) {
            int &p = pri[j];
            int t = i * p;
            if(t > n)
                break;
            pri[t] = 1;
            if(i % p) {
                phi[t] = phi[i] * phi[p];
            } else {
                phi[t] = phi[i] * p;
                break;
            }
        }
    }
    for(int i = 1; i <= n; i++) {
        phi[i] += phi[i - 1];
        if(phi[i] >= mod)
            phi[i] -= mod;
    }
}

/*inline int qpow(ll x, int n) {
    ll res = 1;
    while(n) {
        if(n & 1) {
            res *= x;
            if(res >= mod)
                res %= mod;
        }
        x *= x;
        if(x >= mod)
            x %= mod;
        n >>= 1;
    }
    return res;
}*/

inline int s1(ll n) {
    if(n >= mod)
        n %= mod;
    return n * (n + 1) % mod * inv2 % mod;
}

const int inv6 = 166374059; //qpow(6, mod - 2);
inline int s2(ll n) {
    if(n >= mod)
        n %= mod;
    ll tmp = n * (n + 1);
    if(tmp >= mod)
        tmp %= mod;
    tmp *= n * 2 + 1 ;
    if(tmp >= mod)
        tmp %= mod;
    tmp *= inv6;
    if(tmp >= mod)
        tmp %= mod;
    return tmp;
}

unordered_map<ll, int> Sphi;

inline int Phi(ll n) {
    if(n <= MAXN)
        return phi[n];
    if(Sphi.count(n))
        return Sphi[n];
    int ret = s1(n);
    for(ll l = 2, r, t; l <= n; l = r + 1) {
        t = n / l;
        r = n / t;
        ret -= (r - l + 1) % mod * Phi(t) % mod;
        if(ret < 0)
            ret += mod;
    }
    return Sphi[n] = ret;
}

inline int S(ll n) {
    return (2 * Phi(n) - 1) % mod;
}

inline int Ans(ll n) {
    int res = 0;
    for(ll l = 1, r, t; l <= n; l = r + 1) {
        t = n / l;
        r = n / t;
        ll tmp = s2(r) - s2(l - 1);
        if(tmp < 0)
            tmp += mod;
        tmp *= S(t);
        if(tmp >= mod)
            tmp %= mod;
        res += tmp;
        if(res >= mod)
            res -= mod;
    }
    return res;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
    //freopen("Yinku.out","w",stdout);
#endif // Yinku
    sieve();
    int T = read();
    while(T--) {
        write(Ans(read()));
    }
}

原文地址:https://www.cnblogs.com/Yinku/p/11053309.html

时间: 2024-10-16 12:52:56

SCUT - 354 - CC的简单多项式 - 杜教筛的相关文章

【Luogu3768】简单的数学题(莫比乌斯反演,杜教筛)

[Luogu3768]简单的数学题(莫比乌斯反演,杜教筛) 题面 洛谷 \[求\sum_{i=1}^n\sum_{j=1}^nijgcd(i,j)\] $ n<=10^9$ 题解 很明显的把\(gcd\)提出来 \[\sum_{d=1}^nd\sum_{i=1}^n\sum_{j=1}^nij[gcd(i,j)==d]\] 习惯性的提出来 \[\sum_{d=1}^nd^3\sum_{i=1}^{n/d}\sum_{j=1}^{n/d}ij[gcd(i,j)==1]\] 后面这玩意很明显的来一发

loj#6229. 这是一道简单的数学题 (??反演+杜教筛)

题意:给定\(n\le 10^9\),求:\(F(n)=\sum_{i=1}^n\sum_{j=1}^i\frac{\mathrm{lcm}(i,j)}{\mathrm{gcd}(i,j)}\),对1e9+7取模 推式子: \(F(n)=\sum_{i=1}^n\sum_{j=1}^i\frac{\mathrm{lcm}(i,j)}{\mathrm{gcd}(i,j)}\) \(=\sum_{i=1}^n\sum_{j=1}^i\frac{ij}{\gcd^2(i,j)}\) \(=\sum_{

51nod 1220 约数之和(杜教筛 + 推推推推推公式)

题意 给出\(n(1\leq n \leq 10^9)\),求\(\sum_{i=1}^n\sum_{j=1}^n\sigma(ij)\),其中\(\sigma(n)\)表示\(n\)的约数之和. balabala 交了两道杜教筛的的板子题(51nod 1239, 1244)就看到了这题,然后不会搞,然后看题解看了一天一夜终于彻底搞明白一发A掉了...感觉学到了很多,写个博客整理一下,如有错请指出. 技能需求 数论函数与线性筛 莫比乌斯反演(也可以当成容斥去理解) 狄利克雷卷积 杜教筛 强大的数

杜教筛 学习总结

看了看唐老师的blog,照猫画虎的做了几道题目,感觉对杜教筛有些感觉了 但是稍微有一点难度的题目还是做不出来,放假的时候争取都A掉(挖坑ing) 这篇文章以后等我A掉那些题目之后再UPD上去就好啦 由于懒得去写怎么用编辑器写公式,所以公式就准备直接copy唐老师的啦 首先积性函数和完全积性函数什么的就不再多说了 列举常见的积性函数: 1.约数个数函数和约数个数和函数 2.欧拉函数phi 3.莫比乌斯函数mu 4.元函数e 其中e(n)=[n==1] 5.恒等函数I 其中I(n)=1 6.单位函数

杜教筛进阶+洲阁筛讲解+SPOJ divcnt3

Part 1:杜教筛进阶在了解了杜教筛基本应用,如$\sum_{i=1}^n\varphi(i)$的求法后,我们看一些杜教筛较难的应用.求$\sum_{i=1}^n\varphi(i)*i$考虑把它与$id$函数狄利克雷卷积后的前缀和.$$\sum_{i=1}^n\sum_{d|i}\varphi(d)*d*\frac id=\sum_{i=1}^ni^2$$枚举$T=\frac id$,原式化为$$\sum_{T=1}^nT\sum_{d=1}^{\lfloor\frac nT\rfloor}

莫比乌斯函数与杜教筛

前人的文章已经很详尽了,这里只作一点补充. 莫比乌斯反演与莫比乌斯函数入门资料:https://wenku.baidu.com/view/fbec9c63ba1aa8114431d9ac.html 讲的非常清楚,这里稍微补充一下: 1.虽然考试肯定不会考,但是对于定理的证明还是应该大概了解一下的.关于欧拉函数φ与莫比乌斯函数μ,由于它们都是积性函数,所以很多性质都可以用类似数学归纳法的方法证明.过程是:(1)对于一个性质证明在x为素数是成立 (2)对于素数p和一个正整数a,设此性质对a与p均成立

杜教筛 与 数论函数(狄雷克卷积)

为了改变数论只会GCD的尴尬局面,我们来开一波数论: 数论函数: 数论函数是定义域在正整数的函数. 积性函数: f(ab)=f(a)f(b),gcd(a,b)=1 ,完全积性函数: f(ab)=f(a)f(b) . 常见积性函数: φ(n) ,μ(n) (莫比乌斯函数), d(n) (因子个数), σ(n) (因子和). 单位函数 : e(n)=[n=1] . 常见完全积性函数: Idk(n)=n^k , 1(n)=Id0(n) , Id(n)=Id1(n) . 我们 有以下令人窒息的操作: (

【XSY2721】求和 杜教筛

题目描述 设\(n=\prod a_i^{p_i}\),那么定义\(f_d(n)=\prod{(-1)^{p_i}[p_i\leq d]}\).特别的,\(f_1(n)=\mu(n)\). 给你\(n,k\),求 \[ \sum_{i=1}^n\sum_{j=1}^n\sum_{d=1}^kf_d(\gcd(i,j)) \] \(n\leq {10}^{10},k\leq 40\) 题解 先做一些简单的处理 \[ \begin{align} ans&=\sum_{i=1}^n\sum_{j=1}

卷积 &amp; 杜教筛

卷积 卷积定义: 如果有数论函数\(f, g\), 那么它们卷积的第\(n\)项为\((f * g) (n)\),设这个卷出来的新函数为h,那么有 \[h(n) = \sum_{k | n} f(k) g(n / k) = \sum_{ij = n}f(i) g(j)\] 一些性质: 1,积性函数的卷积还是积性函数 证明: 现有\(f, g\)为积性函数,且\(gcd(p, q) == 1\),求证\(h(p) \cdot h(q) = h(qp).\) \[h(p) \cdot h(q) =