Typesetting math: 100%

数论

数论

逆元

b,m 互质,并且 b|a,则存在一个整数 x 使得

aba×x(modm)

则称 xb 的模 m 乘法逆元,记作 b1(modm)

例如 b=31,m=5,a=93,存在 x=1 满足 933193×1 (mod5)

因为乘法满足模运算的分配律,即 (a×b)modm=((amodm)×(bmodm))modm

而除法不满足,故乘法逆元就可以很好地解决这个问题,即

abmodm=((amodm)×(b1modm))modm

这里介绍三种求逆元的方法:

1.

因为

aba×b1ab×b×b1(modm)

所以

b×b11(modm)

其实也就是要找到一个 x,满足 b×x1(modm)

m 为质数时,根据费马小定理 bmb(modm) 可得:b×bm21(modm)

因此,当模数 m 为质数时,bm2 就是 b 的模 m 乘法逆元。

2.

第一种方法说过,

其实也就是要找到一个 x,满足 b×x1(modm)

也就是解 my+bx=1 这个方程,故我们可以使用扩展欧几里得来求解 x

3.

这里介绍一个线性时间求 1n 在模 m 下的逆元。

我们设 m=q×d+r (r<d)

可以得到;

  1. q×d+r0(modm)
  2. q=md
  3. r=mmodd

对于式子 1. 两边同乘 d1×r1,得到

q×r1+d10(modm)d1q×r1(modm)d1md×(mmodd)1(modm)

故可以根据前面的 (mmodd)1 推出后面的 d1

#include <bits/stdc++.h>
const int N = 3e6 + 10;
using namespace std;

int n, p;
long long ans[N];

int main()
{
    cin >> n >> p;
    ans[1] = 1;
    printf("%lld\n", 1);

    for (int i = 2; i <= n; ++ i)
        ans[i] = ((- (p / i) * ans[p % i]) % p + p) % p,
        printf("%lld\n", ans[i]);

    return 0;
}

扩展欧几里得定理

问题引入

我们要解决一个这样的问题:

ax+by=gcd(a,b)

分析

在欧几里得算法的最后一步,即 b=0 时,显然有一对整数 x=1,y=0 满足 a×1+b×0=gcd(a,0)

我们假设有 x2,y2 满足 bx2+(amodb)y2=gcd(b,amodb)

由于 gcd(a,b)=gcd(b,amodb),故 ax+by=bx2+(amodb)y2

又因为 (amodb)=aab×b

ax+by=bx2+(aabb)y2ax+by=bx2+ay2abby2ax+by=ay2+b(x2aby2)

由于 a=a,b=b,故 x=y2,y=x2aby2,这样从 x=1,y=0 一步一步就可以推到 ax+by=gcd(a,b) 的解。

对于一般的方程 ax+by=c,当且仅当 gcd(a,b)|c 时有解。

我们可以先求出 ax+by=gcd(a,b) 的特殊解 x0,y0,然后令

x=x0×cgcd(a,b),y=y0×cgcd(a,b)

此时 ax+by=cx,y 可能为负数,有的题目会要求 x,y 为正整数,我们可以把原式进行修改,变为

ax+by+kabgcd(a,b)kabgcd(a,b)=ca(x+kbgcd(a,b))+b(ykagcd(a,b))=c

x=x+kbgcd(a,b)y=ykagcd(a,b)

其中 kZ

类欧几里得算法

问题引入

f(a,b,c,n)=ni=0ai+bc

其中 a,b,c,n 是常数,需要 O(logn) 的做法。

acbc,我们可以将 a,bc 取模以简化问题。

考虑到

x=xcc+xmodc

f(a,b,c,n)=ni=0ai+bc=ni=0⎢ ⎢ ⎢ ⎢(acc+amodc)i+(bcc+bmodc)c⎥ ⎥ ⎥ ⎥=n(n+1)2ac+(n+1)bc+f(amodc,bmodc,c,n)

此时一定有 a<cb<c

S(i)=ai+bc1

再进行转化

ni=0ai+bc=ni=0S(i)j=01=S(n)j=0ni=0[jS(i)]

考虑到

jS(i)j+1ai+bcj+1ai+bcj+1ai+bcj+1ai+bcjc+cai+bjc+cai+bjc+cbaijc+cbaijc+cb1<aijc+cb1<aijc+cb1a<i

S(n)j=0ni=0[jS(i)]=S(n)j=0ni=0[i>jc+cb1a]=S(n)j=0(njc+cb1a)=(S(n)+1)nS(n)j=0cj+(cb1)a=(S(n)+1)nf(c,cb1,a,S(n))

f(a,b,c,n)=(S(n)+1)nf(c,cb1,a,S(n))

可以发现,上述式子是一个递归式,我们不断重复上述过程,先取模,后递归,其实就是辗转相除的过程,时间复杂度 O(logn)

拓展

我们再来推导两个变种求和式

g(a,b,c,n)=ni=0iai+bch(a,b,c,n)=ni=0ai+bc2

推导 g

引理 1.

ni=0i2=n(n+1)(2n+1)6

证明如下:

考虑到

(n+1)3=n3+3n2+3n+1

(n+1)3n3=3n2+3n+1n3(n1)3=3(n1)2+3(n1)+12313=3×(21)2+3×(21)+1

将这 n 个等式左右两边相加,得到

(n+1)31=3(12+22++n2)+3(1+2++n)+n

n3+3n2+3n=3(12+22++n2)+3n(1+n)2+n

整理后得

ni=0i2=n(n+1)(2n+1)6

首先和 f 一样,对其取模(根据引理 1. 可将其展开)。

g(a,b,c,n)=ni=0iai+bc=ni=0i⎢ ⎢ ⎢ ⎢(acc+amodc)i+(bcc+bmodc)c⎥ ⎥ ⎥ ⎥=n(n+1)(2n+1)6ac+n(n+1)2bc+g(amodc,bmodc,c,n)

其他部分推导与 f 类似。

S(i)=ai+bc1

g(a,b,c,n)=S(n)j=0ni=0i[jS(i)]=S(n)j=0ni=0i[i>jc+cb1a]

t(j)=jc+cb1a

则有

g(a,b,c,n)=S(n)j=0((t(j)+1)+(t(j)+2)++n)=S(n)j=0((t(j)+1+n)×(nt(j))2)=12(S(n)+1)n(n+1)S(n)j=0(t(j))2S(n)j=0t(j)=12[(S(n)+1)n(n+1)h(c,cb1,a,S(n))f(c,cb1,a,S(n))]

推导 h

同样套路,先取模

h(a,b,c,n)=ni=0ai+bc2=ni=0⎢ ⎢ ⎢ ⎢(acc+amodc)i+(bcc+bmodc)c⎥ ⎥ ⎥ ⎥2=ni=0(iac+bc+(amodc)i+(bmodc)c)2

Q(i)=(amodc)i+(bmodc)c

拆开则有

h(a,b,c,n)=ni=0(i2ac2+bc2+(Q(i))2+2iacbc+2iacQ(i)+2bcQ(i))=n(n+1)(2n+1)6ac2+(n+1)bc2+h(amodc,bmodc,c,n)+n(n+1)acbc+2acg(amodc,bmodc,c,n)+2bcf(amodc,bmodc,c,n)

照样令

S(i)=ai+bc1t(j)=jc+cb1a

发现平方不好处理,将平方转化为加法

n2=2n(n+1)2n=(2ni=0i)n

h(a,b,c,n)=ni=0ai+bc2=ni=02S(i)+1j=0jai+bc=2ni=0S(i)+1j=0jf(a,b,c,n)

现在只要解决前面的式子即可

ni=0S(i)+1j=0j=ni=0S(i)j=0(j+1)=S(n)j=0(j+1)ni=0[j<ai+bc]=S(n)j=0(j+1)(nt(j))=(S(n)+1)n+S(n)(S(n)+1)2ng(c,cb1,a,S(n))f(c,cb1,a,S(n))

综上所述

h(a,b,c,n)=(S(n)+1)(S(n)+2)n2g(c,cb1,a,S(n))2f(c,cb1,a,S(n))f(a,b,c,n)

a=0 时,上述三个式子都可以 O(1) 计算。

代码实现时,因为三个函数交错递归,考虑三个一起整体递归,同步计算,时间复杂度为 O(logn)

Luogu5170

#include <bits/stdc++.h>
const int mod = 998244353;
int InvTwo, InvSix;
inline int read()
{
    int cnt = 0; char ch = getchar(); bool op = 1;
    for (; ! isdigit(ch); ch = getchar())
        if (ch == '-') op = 0;
    for (; isdigit(ch); ch = getchar())
        cnt = cnt * 10 + ch - 48;
    return op ? cnt : - cnt;
}

inline int quick_pow(int a, int b)
{
    int ret = 1;
    for (; b; b >>= 1)
    {
        if (b & 1) ret = 1ll * ret * a % mod;
        a = 1ll * a * a % mod;
    }
    return ret % mod;
}

struct eu
{
    int f, g, h;
};

inline int S(int a, int b, int c, int i)
{
    return ((1ll * a * i + b) / c) - 1;
}

inline eu solve(int a, int b, int c, int n)
{
    if (a == 0)
    {
        eu now = {0, 0, 0};
        now.f = 1ll * (b / c) * (n + 1) % mod;
        now.h = 1ll * (b / c) * (b / c) % mod * (n + 1) % mod;
        now.g = 1ll * n * (n + 1) % mod * InvTwo % mod * (b / c) % mod;
        return now;
    }
    if (a >= c || b >= c)
    {
        eu now = {0, 0, 0};
        now.f = (now.f + 1ll * n * (n + 1) % mod * InvTwo % mod * (a / c) % mod) % mod;
        now.f = (now.f + 1ll * (n + 1) * (b / c) % mod) % mod;
        now.g = (now.g + 1ll * n * (n + 1) % mod * (2 * n + 1) % mod * InvSix % mod * (a / c) % mod) % mod;
        now.g = (now.g + 1ll * n * (n + 1) % mod * InvTwo % mod * (b / c) % mod) % mod;
        now.h = (now.h + 1ll * n * (n + 1) % mod * (2 * n + 1) % mod * InvSix % mod * (a / c) % mod * (a / c) % mod) % mod;
        now.h = (now.h + 1ll * (n + 1) * (b / c) % mod * (b / c) % mod) % mod;
        now.h = (now.h + 1ll * n * (n + 1) % mod * (a / c) % mod * (b / c) % mod) % mod;
        eu nxt = solve(a % c, b % c, c, n);
        now.f = (now.f + nxt.f) % mod;
        now.g = (now.g + nxt.g) % mod;
        now.h = (now.h + nxt.h) % mod;
        now.h = (now.h + 1ll * 2 * (a / c) % mod * nxt.g % mod) % mod;
        now.h = (now.h + 1ll * 2 * (b / c) % mod * nxt.f % mod) % mod;
        return now;
    }
    else
    {
        eu now = {0, 0, 0};
        eu nxt = solve(c, c - b - 1, a, S(a, b, c, n));
        now.f = 1ll * (S(a, b, c, n) + 1) * n % mod;
        now.f = (now.f - nxt.f) % mod;
        now.f = (now.f + mod) % mod;
        now.g = 1ll * InvTwo * ((((1ll * (S(a, b, c, n) + 1) * n % mod * (n + 1) % mod - nxt.h) % mod) - nxt.f) % mod) % mod;
        now.g = (now.g + mod) % mod;
        now.h = (1ll * (S(a, b, c, n) + 1) * (S(a, b, c, n) + 2) % mod * n % mod) % mod;
        now.h = (now.h - 1ll * 2 * nxt.g) % mod;
        now.h = (now.h - 1ll * 2 * nxt.f) % mod;
        now.h = (now.h - now.f) % mod;
        now.h = (now.h + mod) % mod;
        return now;
    }
}

int main()
{
    int t = read();
    InvTwo = quick_pow(2, mod - 2);
    InvSix = quick_pow(6, mod - 2);
    while (t --)
    {
        int n, a, b, c;
        n = read(), a = read(), b = read(), c = read();
        eu ans = solve(a, b, c, n);
        printf("%d %d %d\n", ans.f, ans.h, ans.g);
    }
    return 0;
}

Reference

oi-wiki

中国剩余定理(CRT)

问题引入

我们需要解决满足下列方程组的一个解 x,并且保证所有的 b 都互相互质。

⎪ ⎪ ⎪ ⎪⎪ ⎪ ⎪ ⎪xa1 (mod b1)xa2 (mod b2)             xan (mod bn)

分析

我们考虑设 M=ni=1bimi=Mbitimix1(modbi) 的一个解,则解为:

x=ni=1aimiti

我们现在来证明一下 x 是一个满足条件的解。

证明:

对于任意的 k[1,n]akmktkak(modbk)

akmktk0(modbi)(i[1,k1]  [k+1,n]),故 x 是一个满足条件的解。

我们知道,M0(modbi)(i[1,n]),故 x+kM (kZ) 都是满足答案的解,若题目要求最小正整数解,则:

x=(xmodM+M)modM

#include <bits/stdc++.h>
const int N = 10 + 10;
using namespace std;

int n;
long long M = 1, m[N], t[N], ans;
int a[N], b[N];

inline void exgcd(long long a, long long b, long long &x, long long &y)
{
    if (b == 0)
    {
        x = 1, y = 0;
        return;
    }
    exgcd(b, a % b, x, y);
    long long d = x; x = y; y = d - (a / b) * y;
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++ i)
        cin >> a[i] >> b[i], M = M * a[i];

    for (int i = 1; i <= n; ++ i)
    {
        long long y;
        m[i] = M / a[i];
        exgcd(m[i], a[i], t[i], y);
        ans = (ans + m[i] * t[i] * b[i]) % M;
    }

    cout << (ans + M) % M << endl;

    return 0;
}

拓展中国剩余定理 (EXCRT)

问题引入

我们要解决的还是这么上文那个问题,其中不保证所有的 b 都互相互质。

分析

我们假设已经有一个解 x 满足前 k1 个同余方程,此时我们设 d=lcm{b1,b2,,bk1},显然,x+jd (jZ) 都是满足条件的解。

那么对于第 k 个同余方程,即要满足 x+jdak(modbk),可转换为 jdakx (mod bk),显然,可以用扩展欧几里得来求解 j,若 gcd(d,bk)akx 那么就无解,否则 x=x+jd,d=lcm{b1,b2,,bk},此时的 x 是满足前 k 个方程的,这样一直做到最后就可以求出答案。

#include <bits/stdc++.h>
const int N = 1e5 + 10;
using namespace std;

int n; long long X, m;
long long a[N], b[N];

inline long long exgcd(long long a, long long b, long long &x, long long &y)
{
    if (b == 0)
    {
        x = 1, y = 0;
        return a;
    }
    long long d = exgcd(b, a % b, x, y);
    long long t = x; x = y; y = t - (a / b) * y;
    return d;
}

inline long long quick_mul(long long a, long long b, long long p)
{
    a %= p, b %= p;
    long long res = 0, op = 1;
    if (b < 0) b = -b, op = -1;
    for (; b; b >>= 1)
    {
        if (b & 1) res = (res + a) % p;
        a = (a + a) % p;
    }
    return res * op;
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i] >> b[i];
    X = b[1], m = a[1];

    for (int i = 2; i <= n; ++i)
    {
        long long d, x, y, c = (b[i] - X);
        d = exgcd(m, a[i], x, y);
        x = quick_mul(x, (c / d), (a[i] / d));
        x = (x % (a[i] / d) + (a[i] / d)) % (a[i] / d);
        X = (X + x * m);
        m = m / d * a[i];
        X = (X % m + m) % m;
    }

    cout << X << endl;

    return 0;
}

BSGS

问题引入

我们需要解决 axb(modM) 的一个解 x,其中 a,M 互质。

分析

首先,如果有解,那么解一定在 [0,M] 这个区间内,根据抽屉原理,axmodM 只会有 M 个取值,故 [0,M] 中至少会存在两个相同余数的数,即一定存在一对 i,j 满足 aiaj(modM),那么在 i 之后,aimod M,ai+1mod M,ajmod M 这些数会循环出现,故如果有解,那么解一定在 [0,M] 这个区间内。

我们考虑把 x 进行拆分,x=qmp,其中 m=x+1q[1,m]p[0,m]

显然,qmp 可以表示出 0m 中的所有数。

我们把原式修改一下得到 aqmpb(modM)aqmb×ap(modM)(该步后往前推导需要有乘法逆元)

我们发现 qp 没有关系了,考虑先 O(x) 枚举 p,把 (b×ap)modM 放入哈希表(map 也行),然后再 O(x) 枚举 aqm,找到最小的 q 满足 aqmmodM 在哈希表中出现过,那么 qm+p 就是最小的答案。

#include <bits/stdc++.h>

int p, b, n, m;
std::map <int, int> mp;

inline int quick_pow(int x, long long y)
{
    int res = 1; x %= p;
    for (; y; y >>= 1)
    {
        if (y & 1) res = 1ll * res * x % p;
        x = 1ll * x * x % p;
    }
    return res;
}

int main()
{
    std::cin >> p >> b >> n;

    m = sqrt(p) + 1;
    for (int i = 0; i <= m; ++ i)
        mp[1ll * n * quick_pow(b, i) % p] = i;
    for (int i = 1; i <= m; ++ i)
    {
        if (mp[quick_pow(b, 1ll * i * m)])
        {
            std::cout << 1ll * i * m - mp[quick_pow(b, i * m)] << std::endl;
            return 0;
        }
    }
    std::cout << "no solution" << std::endl;

    return 0;
}

扩展 BSGS

问题引入

我们要解决的还是 axb(modp) 这个问题,只是不满足 ap 互质。

分析

ap 互质,那么就会存在逆元,可以将 x 分解为 qmp 来求解,所以我们要想办法让 a,p 变得互质。

我们考虑把这个式子转化为不定方程,axyp=b,首先,我们求出 d1=gcd(a,p),然后整个式子都除以 d1,若 bd1 互质,那么就无解,否则我们继续求出 d2=gcd(a,p),一直进行下去,直到 ap 互质。

假设进行了 k 次,最后得到式子就是:

akki=1di×axkypki=1di=bki=1di

其中 ap 互质。

我们再化为同余方程的形式:

akki=1di×axkbki=1di⎜ ⎜ ⎜ ⎜modpki=1di⎟ ⎟ ⎟ ⎟

显然,求出

akki=1di

的逆元,然后直接移到右边,直接用 BSGS 来解决,然后最后把答案加上 k 即可。

注意,不保证答案小于 k 的情况,故在消因子前做一下 O(k) 枚举,直接验证 aib(modp),就能避免这种情况。

code

高斯消元

问题引入

给出 n 组方程,每组方程形如 ni=1aixi=bi,要求求出 x1,x2xn 或告知无解。

分析

我们把这些方程转化为矩阵

∣ ∣ ∣ ∣ ∣a1,1a1,2a1,nb1a2,1a1,2a2,nb2an,1an,2an,nbn∣ ∣ ∣ ∣ ∣

我们希望最后的矩阵形如

∣ ∣ ∣ ∣ ∣ ∣ ∣ ∣10000c101000c200100c300010cn100001cn∣ ∣ ∣ ∣ ∣ ∣ ∣ ∣

对于第 i 行就能求出 xi=ci,即可求出解。

流程如下:

  1. 我们从上往下做,先将当前系数绝对值最大的移到当前这一行,减小误差。
  2. 让当前系数化为 1,即让当前行的每一个数都除以当前系数。
  3. 再用当前第 i 行的第 i 个系数(即为 1)消去 j (ji) 的第 i 个系数,把它消为 0

重复做以上的操作,直到做到第 n 行,此时最后的矩阵形如上述。

我们可以在 O(n3) 的时间复杂度完成。

判断解情况:

最后说一下如何判无解和无限解:

  1. 无解:当前行系数全为 0,但值不为 0

  2. 无限解:当前行系数全为 0,且值为 0

一、积性函数

1. 积性函数:

对于任意互质的整数 ab (gcd(a,b)=1) 有性质 f(ab)=f(a)×f(b)

2. 完全积性函数:

对于任意的整数 ab 有性质 f(ab)=f(a)×f(b)

3. 证明 φ(n) 是积性函数。

1. 定理:

gcd(x,y)=1 时,φ(x×y)=φ(x)×φ(y)

2. 证明:

我们将 1x×y 排列成如下方阵:

12iy1+y2+yi+y2×y1+2×y2+2×yi+2×y3×y1+j×y2+j×yi+j×y(j+1)×y1+(x1)×y2+(x1)×yi+(x1)×yx×y

由于 gcd(x,y)=1,每一列 i+j×y 都能构成一个 mody 的完全剩余系 {¯¯¯0,¯¯¯1,,¯¯¯¯¯¯¯¯¯¯¯¯y2¯¯¯¯¯¯¯¯¯¯¯¯y1},则每一列与 y 互质的数就有 φ(y)。同理,对于每一行,都能构成一个 modx 的完全剩余系 {¯¯¯0,¯¯¯1,,¯¯¯¯¯¯¯¯¯¯¯¯¯x2¯¯¯¯¯¯¯¯¯¯¯¯¯x1},并且它们都是对齐的,则每一行与 x 互质的数就有 φ(x)

ax×y 互质,则 ax 互质且 ay 互质,即 φ(x×y)=φ(x)×(y)

二、欧拉函数

1. 欧拉函数的定义及求法

φ(x) 表示有多少个 i (1ix) 满足 gcd(i,x)=1(即有多少个 xix 互质)。

显然当 x 为质数时,φ(x)=x1

x 唯一分解:

x=mi=1pcii

φ(x)=x×mi=1pi1pi

我们来证明一下这个定理:

引理 1:设 x=pk (p 为质数),那么 φ(x)=pk1×(p1)

证明 1:此时对于一个 yx 互质,当且仅当 y≢0(modp),我们考虑将 x 分成许多段,长度为 p,有 xp=pkp=pk1 段。其中每一段都有 p1 个数与 p 互质,有 pk1 段,故 φ(x)=pk1×(p1)

根据欧拉函数的积性性质,我们可以得到:

φ(x)=mi=1φ(pcii)=mi=1pci1×(pi1)=mi=1pcip×(pi1)=mi=1pci×pi1pi=x×mi=1pi1pi

故我们可以使用试除法在 O(x) 的时间内求出 φ(x)

2. 欧拉函数的一些性质

定理 1: n>11n 之间与 n 互质的数的和为:n×φ(n)2

证明:因为 gcd(n,x)=gcd(n,nx),故与 n 不互质的数是成对出现的,且平均值为 n2,又考虑到共有 φ(n) 个与其互质的数,故  n>11n 之间与 n 互质的数的和为 n×φ(n)2

定理 2:当 x 为奇数时,φ(2×x)=φ(x)

证明 2:把 x 唯一分解:

(其中 pi2),2×x=2×mi=1pcii,根据上面的欧拉函数的求法可得:

φ(2×x)=2×x×212×mi=1pi1pi=x×mi=1pi1piφ(x)=x×mi=1pi1pi

所以当 x 为奇数时,φ(2×x)=φ(x)

定理 3:若 x>2 ,那么 φ(x) 是偶数。

证明 3:我们考虑把 x 唯一分解:

x=mi=1pciiφ(x)=x×mi=1pi1pi

显然,除开 2 这个质数以外,其他质数都是奇数,减去 1 之后就都是偶数了,故不包含 2 这个质因子的数的欧拉函数一定是偶数,而 21=1,对结果没有影响,并且如果这个数有 2 这个质因子,那么它一定是偶数,所以若 x>2 ,那么 φ(x) 是偶数。

定理 4:设 p 为质数,若 p|np2|nφ(n)=φ(np)×p

证明 4:由于 p2|n 所以 np 也有 p 这个因子,故 φ(n)φ(np) 的区别只有 nnp 这个乘积的差别,故可得 φ(n)=φ(np)×p

定理 5:设 p 为质数,若 p|np2nφ(n)=φ(np)×(p1)

证明 5:由于 p2n 所以 npp 互质,故 φ(n)φ(np) 的比,多了 p1pp 这两个乘积,故可得:φ(n)=φ(np)×(p1)

定理 6:

x=d|xφ(d)

证明:设 f(n)=d|nφ(d), 根据乘法分配律以及 φ 的积性性质,我们可以得到:若 n,m 互质,则

f(nm)=d|nmφ(d)=d|nφ(d)×d|mφ(d)=f(n)×f(m)

f(n) 是积性函数。对于单个质因子 :

f(pcii)=d|pciiφ(d)=φ(1)+φ(p)++φ(pcii)

我们发现这是一个等比数列求和再加 1,结果为 pci。所以

f(n)=mi=1f(pcii)=mi=1pcii=n

拉格朗日插值

多项式定义

n 次多项式定义为:

f(x)=anxn+an1xn1+an2xn2++a0

问题引入 1

给出 n+1 个点 (xi,yi),表示 f(xi)=yi,要求求出 f(t)

做法 1:

高斯消元。

我们把这 n+1 个点都写出来:

⎪ ⎪ ⎪ ⎪ ⎪⎪ ⎪ ⎪ ⎪ ⎪anxn1+an1xn11+an2xn21++a0=y1    anxn2+an1xn12+an2xn22++a0=y2                                         anxnn+1+an1xn1n+1+an2xn2n+1++a0=yn+1

an,an1,,a0 看作未知量,把 x,y 看作已知量,这样就可以高斯消元进行求解,解出 an,an1,,a0

时间复杂度:O(n3)

做法 2:

拉格朗日插值。

我们从二次多次项入手,我们给出 3 个点,(x1,y1),(x2,y2),(x3,y3)

可以列出方程组:

a2x21+a1x11+a0=y1a2x22+a1x12+a0=y2a2x23+a1x13+a0=y3

这里我们换一种思路,我们构造三个函数,然后相加得到我们要的函数。

构造函数:

f1(x)={1(x=x1)0(xx1),f2(x)={1(x=x2)0(xx2),f3(x)={1(x=x3)0(xx3)

那么当 f(x)=y1f1(x)+y2f2(x)+y3f3(x),此时就满足 x 的取值为 x1,x2,x3 时,f(x) 的取值就为 y1,y2,y3

现在考虑 n 次多项式,给出 n+1 个点:(x1,y1),(x2,y2),,(xn+1,yn+1)

我们考虑构造 f1fn+1

fi(k)=jikxjxixj

fi(k) 满足在 k=xi 时函数值为 1,在 k=xj(ji) 时函数值为 0

那么多项式

f(k)=n+1i=1yifi(k)=n+1i=1yijikxjxixj

就满足当 kx1,x2,,xn+1f(k) 的取值就为 y1,y2,,yn+1

如果我们只要求解特定函数值,我们可以使用逆元来代替除法。

时间复杂度:O(n2)

优化 1

xaa 有关系时,例如 xa=a 时,可以使用前缀乘来优化,时间复杂度:O(n)

优化 2

重心拉格朗日插值法

当我们要解决两个操作:

  1. 往点集里加一个点 (x,y)
  2. 给出一个 k,求出当前点集对应的多项式 f(k) 的值。

考虑把原式子拿去转换。

f(k)=n+1i=1yijikxjxixj=n+1i=1yi×ji(kxj)ji(xixj)=n+1i=1yin+1j=1(kxj)(kxi)ji(xixj)

g(k)=n+1i=1(kxi)

f(k)=g(k)×n+1i=1yi(kxi)ji(xixj)

再记

t(i)=yiji(xixj)

f(k)=g(k)×n+1i=1t(i)kxi

新加点时 O(nlogn) 求出 t(i),故每加一个点就能做到 O(nlogn) 解决。

一些常识

  1. ni=1ik 是一个 k+1 次的多项式,可以插值。
posted @   chzhc  阅读(109)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
levels of contents
点击右上角即可分享
微信分享提示