BZOJ2154 Crash的数字表格及 BZOJ2693 JZPTAB

本文详细解析了两道复杂的数学竞赛题目,包括BZOJ2154和BZOJ2693,通过数论变换和莫比乌斯反演等高级技巧,展示了如何将原问题转化为易于解决的形式,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

做这两道题做得心力交瘁,太恶心了,好久没做数学题,套路差点都全忘光了,推式子的时候犯了一堆错:

  • 没有注意是否仍然满足乘法分配率
  • 模数看错

Problem

BZOJ2154

∑ i = 1 n ∑ j = 1 m l c m ( i , j ) \sum_{i=1}^n\sum_{j=1}^m lcm(i,j) i=1nj=1mlcm(i,j)

Solution

变一下原式

∑ i = 1 n ∑ j = 1 m i j gcd ⁡ ( i , j ) \sum_{i=1}^n\sum_{j=1}^m \frac {ij} {\gcd(i,j)} i=1nj=1mgcd(i,j)ij

∑ d = 1 n ∑ i = 1 n ∑ j = 1 m [ gcd ⁡ ( i , j ) = d ] i j d \sum_{d=1}^n \sum_{i=1}^n\sum_{j=1}^m [\gcd(i,j)=d]\frac {ij} d d=1ni=1nj=1m[gcd(i,j)=d]dij

∑ d = 1 n ∑ i = 1 n / d ∑ j = 1 m / d [ gcd ⁡ ( i , j ) = 1 ] i j d \sum_{d=1}^n \sum_{i=1}^{n/d}\sum_{j=1}^{m/d} [\gcd(i,j)=1] ijd d=1ni=1n/dj=1m/d[gcd(i,j)=1]ijd

∑ d = 1 n d ∑ i = 1 n / d ∑ j = 1 m / d [ gcd ⁡ ( i , j ) = 1 ] i j \sum_{d=1}^n d\sum_{i=1}^{n/d}\sum_{j=1}^{m/d} [\gcd(i,j)=1] ij d=1ndi=1n/dj=1m/d[gcd(i,j)=1]ij


x = n / d , y = m / d x=n/d,y=m/d x=n/d,y=m/d,那么我们来考虑下式怎么计算:

∑ i = 1 x ∑ j = 1 y [ gcd ⁡ ( i , j ) = 1 ] i j \sum_{i=1}^x\sum_{j=1}^y [\gcd(i,j)=1]ij i=1xj=1y[gcd(i,j)=1]ij

F ( d ) = ∑ i = 1 x ∑ j = 1 y [ gcd ⁡ ( i , j ) = d ] i j F(d)=\sum_{i=1}^x\sum_{j=1}^y[\gcd(i,j)=d]ij F(d)=i=1xj=1y[gcd(i,j)=d]ij

G ( x ) = ∑ x ∣ d F ( d ) G(x)=\sum_{x|d} F(d) G(x)=xdF(d)

通过莫反我们可以知道 F ( n ) = ∑ n ∣ d μ ( d n ) G ( d ) F(n)=\sum_{n|d} \mu(\frac d n)G(d) F(n)=ndμ(nd)G(d),为了方便表达,我们记 S ( n ) = ∑ i = 1 n i = n ( n + 1 ) 2 S(n)=\sum_{i=1}^n i=\frac {n(n+1)} 2 S(n)=i=1ni=2n(n+1)

G ( d ) = ∑ i = 1 x ∑ j = 1 y [ d ∣ gcd ⁡ ( i , j ) ] i j = d 2 ∑ i = 1 x / d ∑ j = 1 y / d i j = d 2 S ( x d ) S ( y d ) G(d)=\sum_{i=1}^x\sum_{j=1}^y[d|\gcd(i,j)]ij=d^2\sum_{i=1}^{x/d}\sum_{j=1}^{y/d} ij=d^2S(\frac x d)S(\frac y d) G(d)=i=1xj=1y[dgcd(i,j)]ij=d2i=1x/dj=1y/dij=d2S(dx)S(dy)

我们要求的就是
F ( 1 ) = ∑ i = 1 x μ ( i ) G ( i ) = ∑ i = 1 x μ ( i ) i 2 S ( x i ) S ( y i ) F(1)=\sum_{i=1}^x \mu(i)G(i)=\sum_{i=1}^x\mu(i) i^2S(\frac x i)S(\frac y i) F(1)=i=1xμ(i)G(i)=i=1xμ(i)i2S(ix)S(iy)

数论分块之,一次计算 O ( n ) O(\sqrt n) O(n )


∑ d = 1 n d F ( 1 ) = ∑ d = 1 n d ∑ i = 1 x μ ( i ) G ( i ) \sum_{d=1}^ndF(1)=\sum_{d=1}^nd\sum_{i=1}^{x} \mu(i)G(i) d=1ndF(1)=d=1ndi=1xμ(i)G(i)

∑ d = 1 n d ∑ i = 1 x μ ( i ) i 2 S ( x i ) S ( y i ) \sum_{d=1}^nd\sum_{i=1}^x\mu(i) i^2S(\frac x i)S(\frac y i) d=1ndi=1xμ(i)i2S(ix)S(iy)

x x x分块,然后调用上一个讨论的计算函数计算后面式子的值

O ( n × n ) = O ( n ) O(\sqrt n\times \sqrt n)=O(n) O(n ×n )=O(n)

Code

#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=10000010,mod=20101009;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
int n,m,tot,ans,pri[maxn],vis[maxn],mu[maxn],sqr[maxn];
int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
void init()
{
	mu[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!vis[i]) mu[i]=mod-1,pri[++tot]=i;
		for(int j=1;j<=tot&&i*pri[j]<=n;j++)
		{
			vis[i*pri[j]]=1;
			mu[i*pri[j]]=dec(0,mu[i]);
			if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
		}
	}
	for(int i=1;i<=n;i++) sqr[i]=(sqr[i-1]+(ll)i*i%mod*mu[i])%mod;
}
int query(int x,int y)
{
	int res=0;
	for(int i=1,j,tmp;i<=x;i=j+1)
	{
		j=min(x/(x/i),y/(y/i));
		tmp=((ll)(x/i+1)*(x/i)/2%mod)*((ll)(y/i+1)*(y/i)/2%mod)%mod;
		res=(res+(ll)tmp*dec(sqr[j],sqr[i-1]))%mod;
	}
	return res;
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	#endif
	read(n);read(m);
	if(n>m) swap(n,m);
	init();
	for(int i=1,j,tmp;i<=n;i=j+1)
	{
		j=min(n/(n/i),m/(m/i));
		tmp=(ll)(i+j)*(j-i+1)/2%mod;
		ans=(ans+(ll)tmp*query(n/i,m/i))%mod;
	}
	printf("%d\n",ans);
	return 0;
}

Problem

BZOJ2693
同上题,有 1 0 4 10^4 104组询问。

Solution

直接拿之前那题的结论接着做:
∑ d = 1 n d ∑ i = 1 n / d μ ( i ) i 2 S ( n i d ) S ( m i d ) \sum_{d=1}^n d\sum_{i=1}^{n/d} \mu(i)i^2 S(\frac n {id})S(\frac m {id}) d=1ndi=1n/dμ(i)i2S(idn)S(idm)

枚举 i d id id

∑ i d = 1 n S ( n i d ) S ( m i d ) ∑ i ∣ i d μ ( i ) i 2 × i d i \sum_{id=1}^nS(\frac n {id}) S(\frac m {id})\sum_{i|id} \mu(i)i^2\times \frac {id} i id=1nS(idn)S(idm)iidμ(i)i2×iid

∑ i d = 1 n S ( n i d ) S ( m i d ) ∑ i ∣ i d i d μ ( i ) i \sum_{id=1}^nS(\frac n {id}) S(\frac m {id})\sum_{i|id} id\mu(i)i id=1nS(idn)S(idm)iididμ(i)i

后面的是个积性函数,前面的数论分块。

注意 i d id id不能拆出第二个求和,否则会不满足乘法分配率导致分块做的前缀和有问题。。

时间复杂度 O ( n + m n ) O(n+m\sqrt n) O(n+mn )

Code

#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=10000010,mod=1e8+9;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
int z,n,m,tot,ans,pri[maxn],vis[maxn],val[maxn];
int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
void init()
{
	val[1]=1;
	for(int i=2;i<=10000000;i++)
	{
		if(!vis[i]) val[i]=dec(i,(ll)i*i%mod),pri[++tot]=i;
		for(int j=1;j<=tot&&i*pri[j]<=10000000;j++)
		{
			vis[i*pri[j]]=1;
			if(i%pri[j]==0){val[i*pri[j]]=(ll)val[i]*pri[j]%mod;break;}
			val[i*pri[j]]=(ll)val[i]*val[pri[j]]%mod;
		}
	}
	for(int i=2;i<=10000000;i++) val[i]=pls(val[i],val[i-1]);
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	#endif
	read(z);
	init();
	while(z--)
	{
		read(n);read(m);ans=0;
		if(n>m) swap(n,m);
		for(int i=1,j,tmp;i<=n;i=j+1)
		{
			j=min(n/(n/i),m/(m/i));
			tmp=((ll)(n/i)*(n/i+1)/2%mod)*((ll)(m/i)*(m/i+1)/2%mod)%mod;
			ans=(ans+(ll)tmp*dec(val[j],val[i-1]))%mod;
		}
		printf("%d\n",ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值