【bzoj3601】一个人的数论(莫比乌斯反演+拉格朗日插值)

传送门

题意:
求\[
\sum_{i=1}^{n}i^d[gcd(i,n)=1]
\]

思路:
我们对上面的式子进行变换,有:
\[
\begin{aligned}
&\sum_{i=1}^{n}i[gcd(i,n)=1]\=&\sum_{i=1}^{n}i\sum_{x|gcd(i,n)}\mu (x)\=&\sum_{i=1}^n i\sum_{x|i,x|n}\mu(x)\=&\sum_{x|n}\mu(x)x^d\sum_{i=1}^{\frac{n}{x}}i^d
\end{aligned}
\]

以上都是一些套路,接下来才步入正题。
因为形如\(\sum_{i=1}^n i^d\)这种都是一个以\(n\)为自变量的,最高项次数为\(d+1\)的多项式。

到这步后,我们将后面的形式化,即将多项式表示出来,设\(a_i\)为相关系数,那么就有式子等于:
\[
\sum_{x|n}\mu(x)x^d\sum_{i=0}^{d+1}a_i\lfloor\frac{n}{x}\rfloor^i
\]
变化一下有:
\[
\sum_{i=0}^{d+1}a_i\sum_{x|n}\mu(x)x^d\lfloor\frac{n}{x}\rfloor^i
\]

这里面前面的\(a_i\)为多项式的系数,是未知的。
但其实因为我们知道多项式的形式为\(\sum_{i=0}^{d+1}a_ix^i\),我们可以直接把\(x=1,x=2,\cdots,x=d+1\)的值求出来,然后高斯消元求解系数。
这里也可以利用拉格朗日插值来求解,代码是直接抄yyb(orz)的,思路应该是利用一下等式来求系数:
\[
\sum_{i=0}^n y_i\prod_{i!=j}\frac{x-x_j}{x_i-x_j}
\]

那么现在主要就是后面一部分的计算,我们令\(f(x)=\mu(x)x^d,g(x)=x^i\),那么后面一部分可以写为:\(\sum_{x|n}f(x)g(\frac{n}{x})\),这是狄利克雷卷积的的形式,因为\(f,g\)都为积性,那么\(h=f*g(n)\)也为积性。
所以\(h(n)=\sum_{x|n}\mu(x)x^d\lfloor\frac{n}{x}\rfloor^i\)也为积性函数,那么我们可以考虑单独素因子的贡献。显然每个素因子只会出现\(0\)次或者\(1\)次,否则贡献为\(0\),那么有:
\[
\begin{aligned}
h(p^a)&=\sum_{j=0}^{a}\mu(p^j)p^{jd}(\frac{p^a}{p^j})^i\&=p^{ai}-p^{ai}p^{d-i}
\end{aligned}
\]

那么对于每个\(i,0\leq i\leq d+1\),求出相应的\(h(n)\),再与系数相乘最终结果就出来了。

感觉解法中将多项式形式化出来的想法很巧妙!没想到多项式还能这么用hhh,直接求解多项式的系数也是之前没想到的。之后对卷积的观察也很重要。
很好的一个题。细节参考代码:

/*
 * Author:  heyuhhh
 * Created Time:  2019/11/21 19:44:08
 */
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1000 + 5, MOD = 1e9 + 7;

ll qpow(ll a, ll b) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = ans * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return ans;
}
//求d次多项式系数
struct Lagrange {
    ll f[N], a[N], b[N];
    int d;
    void init(int _d) {
        d = _d;
        //y_i
        for(int i = 1; i <= d + 1; i++) f[i] = (f[i - 1] + qpow(i, d - 1)) % MOD;
        b[0] = 1;
    }
    void work() {
        for(int i = 0; i <= d; i++) {
            for(int j = i + 1; j; j--) b[j] = (b[j - 1] + MOD - 1ll * b[j] * (i + 1) % MOD) % MOD;
            b[0] = 1ll * b[0] * (MOD - i - 1) % MOD;
        }
        for(int i = 0; i <= d; i++) {
            int s = f[i + 1], inv = qpow(i + 1, MOD - 2);
            for(int j = 0; j <= d; j++) if(i != j) s = 1ll * s * qpow((i - j + MOD) % MOD, MOD - 2) % MOD;
            b[0] = 1ll * b[0] * (MOD - inv) % MOD;
            for(int j = 1; j <= d + 1; j++) b[j] = (MOD - 1ll * (b[j] + MOD - b[j - 1]) * inv % MOD) % MOD;
            for(int j = 0; j <= d + 1; j++) a[j] = (a[j] + 1ll * s * b[j]) % MOD;
            for(int j = d + 1; j; j--) b[j] = (b[j - 1] + MOD - 1ll * b[j] * (i + 1) % MOD) % MOD;
            b[0] = 1ll * b[0] * (MOD - i - 1) % MOD;
        }
    }
}A;

int d, w;
ll prod[N];

void run(){
    A.init(d + 1);
    A.work();
    for(int i = 0; i <= d + 1; i++) prod[i] = 1;
    while(w--) {
        int p, a; cin >> p >> a;
        for(int i = 0; i <= d + 1; i++) {
            ll res = (qpow(p, 1ll * a * i) - qpow(p, 1ll * a * i + d) * qpow(qpow(p, i), MOD - 2) % MOD + MOD) % MOD;
            prod[i] = prod[i] * res % MOD;
        }
    }
    ll ans = 0;
    for(int i = 0; i <= d + 1; i++) ans = (ans + A.a[i] * prod[i] % MOD) % MOD;
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    while(cin >> d >> w) run();
    return 0;
}

原文地址:https://www.cnblogs.com/heyuhhh/p/11909180.html

时间: 2024-11-23 21:18:02

【bzoj3601】一个人的数论(莫比乌斯反演+拉格朗日插值)的相关文章

[bzoj3601] 一个人的数论 [莫比乌斯反演+高斯消元]

题面 传送门 思路 这题妙啊 先把式子摆出来 $f_n(d)=\sum_{i=1}^n[gcd(i,n)==1]i^d$ 这个$gcd$看着碍眼,我们把它反演掉 $f_n(d)=\sum_{i=1}^n\sum_{j|i,j|n}\mu(j)i^d=\sum_{j|n}\mu(j)\sum_{i=1}^{\frac{n}{j}}(ij)^d=\sum_{j|n}\mu(j)j^d\sum_{i=1}^{\frac{n}{j}}i^d$ 那么最后面这个东西就是个自然数幂求和了 在这篇关于斯特林数的

【bzoj3601】一个人的数论 莫比乌斯反演+高斯消元

题目描述 题解 莫比乌斯反演+高斯消元 (前方高能:所有题目中给出的幂次d,公式里为了防止混淆,均使用了k代替) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const ll mod = 1000000007; ll a[110][110] , p[1010] , v[1010]; ll pow(ll x , ll

【bzoj4176】Lucas的数论 莫比乌斯反演+杜教筛

题目描述 去年的Lucas非常喜欢数论题,但是一年以后的Lucas却不那么喜欢了. 在整理以前的试题时,发现了这样一道题目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的约数个数.他现在长大了,题目也变难了. 求如下表达式的值: 其中f(ij)表示ij的约数个数. 他发现答案有点大,只需要输出模1000000007的值. 输入 第一行一个整数n. 输出 一行一个整数ans,表示答案模1000000007的值. 样例输入 2 样例输出 8 题解 莫比乌斯反演+杜教筛 首先有个神奇

[SPOJ VLATTICE]Visible Lattice Points 数论 莫比乌斯反演

7001. Visible Lattice Points Problem code: VLATTICE Consider a N*N*N lattice. One corner is at (0,0,0) and the opposite one is at (N,N,N). How many lattice points are visible from corner at (0,0,0) ? A point X is visible from point Y iff no other lat

学习笔记--数论--莫比乌斯反演初认识

前言 本文只是用比较通俗的例子让大家了解一下什么是莫比乌斯反演,其中说明 (明明都是瞎猜)可能有纰漏.本人也是个蒟蒻,未能给出珂学证明,还望多多指教. 理论基础 "|"符号表示整除, a|b 表示b被a整除,也就是b有a这个因数,b=ka (k∈N). "∑ "求和符号 是什么 请先看这个例子: 假设有两个函数F(n),f(d),且d∈{x| x|n(即n被d整除)} 并有以下关系:F(n)等于所有f(d)之和. 比如:6能被1,2,3,6整除,所以F(6)=f(1

组合 数论 莫比乌斯反演 hdu1695

题解:https://blog.csdn.net/lixuepeng_001/article/details/50577932 题意:给定范围1-b和1-d求(i,j)=k的数对的数量 #include<cstdio> #include<iostream> #include<cstdlib> #include<cmath> #include<cstring> using namespace std; const int MAXN = 100000

模板 - 数学 - 数论 - 莫比乌斯反演 - 2

示例: 1.经典问题 求 $f(x,n,m)=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[gcd(i,j)==x]$ : 答案: $f(x,n,m) = \sum\limits_{k=1}\mu(k){\lfloor{\frac{n}{kx}}}\rfloor{\lfloor{\frac{m}{kx}}\rfloor}$ 构造: $F(x,n,m) = \sum\limits_{x|d}f(d) = \sum\limits_{k=1}f(kx) =\su

【bzoj 4176】 Lucas的数论 莫比乌斯反演(杜教筛)

Description 去年的Lucas非常喜欢数论题,但是一年以后的Lucas却不那么喜欢了. 在整理以前的试题时,发现了这样一道题目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的约数个数.他现在长大了,题目也变难了. 求如下表达式的值: 一行一个整数ans,表示答案模1000000007的值. Sample Input 2 Sample Output 8 HINT 对于100%的数据n <= 10^9. 题解: 解锁新技能:杜教筛. 再复习一下: 若$F(n)=\s

BZOJ 4176 Lucas的数论 莫比乌斯反演

题目大意:给定n(n≤109),求∑ni=1∑nj=1d(ij) 推错式子害死人... 由d|ij等价于dgcd(i,d)|j可得 ∑ni=1∑nj=1d(ij) =∑ni=1∑n2d=1?n?gcd(i,d)d? =∑nd=1∑?nd?i=1∑?n2d?j=1?nj?[gcd(i,j)=1] =∑nd=1∑?nd?i=1∑nj=1?nj?[gcd(i,j)=1] =∑nd=1∑?nd?i=1∑nj=1?nj?∑k|i,k|jμ(k) =∑nk=1μ(k)(∑?nk?d=1?nkd?)2 O(n