和式的变换以及几道例题

和式的变换与推导例题

规则

kKcak=ckKak

kK(ak+bk)=kKak+kKbk

kKak=p(k)Kap(k) 交换律。p(k) 是下标排列

和式的变换技术

1. 替换条件式

i=1nj=1md|gcd(i,j)d=i=1nj=1md=1n[d|i][d|j]d

暴力枚举

2. 替换指标变量

i=1nj=1m[gcd(i,j)=k]=ik=1njk=1m[gcd(ik,jk)=k]=ik=1njk=1m[gcd(i,j)=1]

具体证明……

3. 交换求和次序

i=1nj=1mA(i)B(i)=j=1mi=1nA(i)B(i)

4. 分离变量

i=1nj=1mA(i)B(i)=i=1nA(i)j=1mB(i)

感性理解即可

例题

1#P3455 [POI2007]ZAP-Queries

题意:给出 n,m,k,求 i=1nj=1m[gcd(i,j)=k]。数据规模 1kn,m5104,T=5104

用到莫比乌斯函数的性质 d|nμ(d)=[n=1]
此处应用: [gcd(i,j)=1]=d|gcd(i,j)μ(d)

那么

i=1nj=1m[gcd(i,j)=1]=i=1nj=1md|gcd(i,j)μ(d)=i=1nj=1md=1n[d|i][d|j]μ(d)=d=1nμ(d)i=1n[d|i]j=1m[d|j]=d=1nμ(d)ndmd

算莫比乌斯函数的前缀和,后两项是数论分块。整除分块 i=1nf(i)ni

那么现在再来看复杂情况:

i=1nj=1m[gcd(i,j)=k]=ik=1njk=1m[gcd(ik,jk)=k]=i=1nkj=1mk[gcd(i,j)=1]

同理导出莫比乌斯函数,最终

d=1nkμ(d)nkdmkd

莫比乌斯函数用线性筛即可。

2#P2257 YY的GCD

题意:给出 n,mi=1nj=1m[gcd(i,j)prime]

i=1nj=1m[gcd(i,j) prim ]=i=1nj=1mk=1n[gcd(i,j)=k][k prim ]=k=1ni=1|nk|j=1|mk|[gcd(i,j)=1][k prim ]=k=1ni=1|nk|j=1|mk|dgcd(i,j)μ(d)[k prim ]=k=1ni=1|nk|j=1|mk|d=1|nk|[di][dj]μ(d)[k prim ]=k=1nd=1|nk|μ(d)i=1|nk|[di]j=1|mk|[dj][k prim ]=k=1nd=1nkμ(d)nkdmkd

发现无法整除分块,分母是两个变量

T=kd,则 d=T/k

=k=1nTknkμ(Tk)nTmT [kprime]=k=1nT=1nμ(Tk)nTmT [kprime]=T=1nnTmTk=1nμ(Tk) [kprime]=T=1nnTmTkprimeμ(Tk)

F(T)=kprimeμ(Tk)

则原式化为:

T=1nF(T)nTmT

F(T) 需要预处理

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define LL long long
const int N = 10000010;
int vis[N], p[N], mu[N], cnt;
int F[N];

void init()
{
    mu[1] = 1;
    for (int i = 2; i < N; i++)
    {
        if (!vis[i])
            p[++cnt] = i, mu[i] = -1;
        for (int j = 1; i * p[j] < N; j++)
        {
            vis[i * p[j]] = 1;
            if (i % p[j] == 0)
                break;
            mu[i * p[j]] = -mu[i];
        }
    }
    for (int i = 1; i <= cnt; i++)
        for (int j = p[i]; j < N; j += p[i])
        // j 和 pi 只能是整数倍
            F[j] += mu[j / p[i]];
    for (int i = 1; i < N; i++)
        F[i] += F[i - 1];
}
LL calc(int n, int m)
{
    if (n > m)
        swap(n, m);
    LL ans = 0;
    for (int l = 1, r; l <= n; l = r + 1)
    {
        r = min(n / (n / l), m / (m / l));
        ans += 1ll * (F[r] - F[l - 1]) * (n / l) * (m / l);
    }
    return ans;
}
int main()
{
    init();
    int n, m, T;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d%d", &n, &m);
        printf("%lld\n", calc(n, m));
    }
}

3#P3327 [SDOI2015] 约数个数和

题意:设 d(x)x 的约数个数。给定 n,mi=1nj=1md(ij)T 组询问,T,n,m5104

结论:d(ij)=x|iy|j[gcd(x,y)=1] 证明参考,和数学一本通莫比乌斯反演

证明看不懂,背下来吧。

最后化为 d=1nμ(d)F(nd)F(md)

那么预处理 μF,预处理 F 需要用到一次数论分块,计算结果时还需要用到一次数论分块。

#include <bits/stdc++.h>
#define rei register int
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define rep(i, s, n, c) for (register int i = s; i <= n; i+=c)
#define repd(i, s, n, c) for (register int i = s; i >= n; i-=c)
#define CHECK cout<<"WALKED"<<endl;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
#define pb push_back
#define ls id<<1
#define rs id<<1|1
const int INF = INT_MAX;
long long binpow(long long a, long long b, ll mod){long long res = 1;  while (b > 0){if (b & 1) res = res * a % mod;a = a * a % mod;  b >>= 1;  }  return res;}

using namespace std;
const int maxn = 50005;
int vis[maxn], p[maxn], mu[maxn], cnt;
ll F[maxn];
void init()
{
	mu[1]=1;
	rep (i, 2, maxn - 1, 1) {
		if (!vis[i]) {
			p[++cnt] = i;
			mu[i]= -1;
		}
		for (int j = 1; i * p[j] < maxn; j++) {
			vis[i * p[j]] = 1;
			if (i % p[j] == 0) break;
			mu[i * p[j]] = -mu[i];
		}
	}
	rep (i, 1, maxn - 1, 1) {
		mu[i] += mu[i - 1]; // mobius prefixsum
	}
	rep (i, 1, maxn - 1, 1) {
		int r;
		rep(l, 1, i, -l + r + 1) {
			r = (i / (i / l));
			F[i] += 1ll * (r - l + 1) * (i / l);
		}
	}
}
ll cc(int n, int m)
{
	if (n > m) swap(n, m);
	ll ans = 0;
	int r;
	rep (l, 1, n, -l + r + 1) {
		r = min(n / (n / l), m / (m / l));
		ans += (mu[r] - mu[l - 1]) * F[n/l] * F[m/l];
		// 下标整除也可以分块
	}
	return ans;
}
int main()
{
	init();
	int n, m, T = read();
	while (T--) {
		n = read(), m = read();
		printf("%lld\n", cc(n,m));
	}
    return 0;
}

最后整理一下

待做题目:P2522

posted @   Vegdie  阅读(362)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示