【2020杭电第九场】【HDU 6855】Absolute Math

Description

定义: f ( x ) = ∑ d ∣ n ∣ μ ( d ) ∣ f(x)=\sum_{d|n}|\mu(d)| f(x)=dnμ(d)
F ( n , m ) = ∑ i = 1 m f ( i n ) F(n,m)=\sum_{i=1}^mf(in) F(n,m)=i=1mf(in)
答案要求
A n s = F ( n , m ) Ans=F(n,m) Ans=F(n,m)
n , m ≤ 1 0 7 n,m\leq10^7 n,m107

Solution

显然的, f ( x ) f(x) f(x)是一个积性函数,即 f ( x y ) = f ( x ) f ( y ) , 当 gcd ⁡ ( x , y ) = 1 f(xy)=f(x)f(y),当\gcd(x,y)=1 f(xy)=f(x)f(y),gcd(x,y)=1
又有 f ( n i ) = f ( n ) f ( i ) / f ( gcd ⁡ ( n , i ) ) f(ni)=f(n)f(i)/f(\gcd(n,i)) f(ni)=f(n)f(i)/f(gcd(n,i))
可以将上试改写:
f ( n i ) = f ( n ) f ( i ) / f ( gcd ⁡ ( i , n ) ) = f ( n ) f ( i ) ∗ ∑ T ∣ n , T ∣ i 1 f ( T ) ∑ T d ∣ n , T d ∣ i μ ( d ) f(ni)=f(n)f(i)/f(\gcd(i,n))=f(n)f(i)*\sum_{T|n,T|i}\frac{1}{f(T)}\sum_{Td|{n,Td|i}}\mu(d) f(ni)=f(n)f(i)/f(gcd(i,n))=f(n)f(i)Tn,Tif(T)1Tdn,Tdiμ(d)
所以
f ( n i ) = f ( n ) f ( i ) ∗ ∑ T ∣ n , T ∣ i ∑ d ∣ T 1 f ( d ) μ ( T d ) f(ni)=f(n)f(i)*\sum_{T|n,T|i}\sum_{d|T}\frac{1}{f(d)}\mu(\frac{T}{d}) f(ni)=f(n)f(i)Tn,TidTf(d)1μ(dT)
g ( n ) = ∑ d ∣ n 1 f ( d ) μ ( n d ) g(n)=\sum_{d|n}\frac{1}{f(d)}\mu(\frac{n}{d}) g(n)=dnf(d)1μ(dn)
所以
f ( n i ) = f ( n ) f ( i ) ∗ ∑ T ∣ n , T ∣ i g ( T ) f(ni)=f(n)f(i)*\sum_{T|n,T|i}g(T) f(ni)=f(n)f(i)Tn,Tig(T)
所以
A n s = f ( n ) ∑ d ∣ n g ( d ) ∑ i = 1 ⌊ m d ⌋ f ( i d ) = f ( n ) ∑ d ∣ n g ( d ) F ( d , ⌊ m d ⌋ ) Ans=f(n)\sum_{d|n}g(d)\sum_{i=1}^{\lfloor\frac{m}{d}\rfloor}f(id)=f(n)\sum_{d|n}g(d)F(d,\lfloor\frac{m}{d}\rfloor) Ans=f(n)dng(d)i=1dmf(id)=f(n)dng(d)F(d,dm)

对于 g ( 1... n ) g(1...n) g(1...n),我们可以在 O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n))的时间内全部算出,

现在问题就变成了如果快速求 F ( d , ⌊ m d ⌋ ) F(d,\lfloor\frac{m}{d}\rfloor) F(d,dm)

我们考虑对于一组数据,最暴力的求法复杂度是多少(即暴力循环求和):
∑ d = 1 n ⌊ m d ⌋ ≤ 1 0 7 log ⁡ ( 1 0 7 ) \sum_{d=1}^n\lfloor\frac{m}{d}\rfloor \leq10^7\log(10^7) d=1ndm107log(107)
所有我们可以将多组询问中所有的 F ( d , ⌊ m d ⌋ ) F(d,\lfloor\frac{m}{d}\rfloor) F(d,dm)全部离线,只用 O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n))的时间便可以全部求出来,

总复杂度: O ( n log ⁡ ( n ) + ∑ D ( n ) ) O(n\log(n)+\sum D(n)) O(nlog(n)+D(n)) D ( n ) D(n) D(n)表示n的约数个数)

Code

#include <bits/stdc++.h>
#define fo(i,a,b)  for(int i=a;i<=b;++i)
#define fod(i,a,b)  for(int i=a;i>=b;--i)
using namespace std;
typedef long long LL;
const int N=1000500,M=10000500,mo=1e9+7;
int read(int &n)
{
	bool q=0;n=0;char ch=' ';
	for(;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());
	if(ch=='-')ch=getchar(),q=1;
	for(;ch<='9'&&ch>='0';ch=getchar())n=(n<<1)+(n<<3)+ch-48;
	return q?n=-n:n;
}
int n,m,ans;
int pr[N],mu[M];
bool prz[M];
int f[M],g[M];
int er[101],er1[101];
LL Ans[N];
int a[N];
struct qqww
{
	int d,i,m;
}d[N*3];
int d0;
LL ksm(LL q,int w)
{
	LL ans=1;
	for(;w;w>>=1,q=q*q%mo)if(w&1)ans=ans*q%mo;
	return ans;	
}
void Pre(int n)
{
	mu[1]=1;
	fo(i,2,n)
	{
		if(!prz[i])pr[++pr[0]]=i,mu[i]=-1,f[i]=1;
		fo(j,1,pr[0])
		{
			int t=pr[j]*i;
			if(t>n)break;
			prz[t]=1;
			f[t]=f[i];
			if(i%pr[j]==0)break;
			f[t]=f[i]+1,mu[t]=-mu[i];
		}
	}
}
bool PX(qqww q,qqww w){return q.d<w.d||(q.d==w.d&&q.m<w.m);}
int main()
{
	int q,w,_;
	int SRT=clock();
	q=100;
	er[0]=1;fo(i,1,q)((er[i]=er[i-1]<<1)>=mo?er[i]-=mo:0);
	er1[q]=ksm(er[q],mo-2);
	fod(i,q-1,0)((er1[i]=er1[i+1]<<1)>=mo?er1[i]-=mo:0);
	Pre(1e7);
	int mx=0;
	read(_);
	fo(I,1,_)
	{
		a[I]=read(n),read(m);
		mx=max(n,mx);
		mx=max(m,mx);
		for(int i=1;i*i<=n;++i)if(n%i==0)
		{
			d[++d0].d=i;
			d[d0].m=m/i;
			d[d0].i=I;
			if(i*i==n)continue;
			d[++d0].d=n/i;
			d[d0].m=m/(n/i);
			d[d0].i=I;
		}
	}
	// cerr<<clock()-SRT<<endl;
	fo(i,1,mx)if(mu[i])
	{
		if(mu[i]<0)
		{
			for(int j=1,k=i;k<=mx;++j,k+=i)((g[k]-=er1[f[j]])<0?g[k]+=mo:0);
		}else {
			for(int j=1,k=i;k<=mx;++j,k+=i)((g[k]+=er1[f[j]])>=mo?g[k]-=mo:0);
		}
	}
	fo(i,1,mx)f[i]=er[f[i]];
	sort(d+1,d+1+d0,PX);
	LL t=0,j=1;
	// cerr<<clock()-SRT<<endl;
	fo(I,1,d0)
	{
		if(d[I].d!=d[I-1].d)t=0,j=1;
		for(;j<=d[I].m;++j)
		{
			(t+=f[j*d[I].d])>=mo?t-=mo:0;
		}
		Ans[d[I].i]=(Ans[d[I].i]+t*g[d[I].d])%mo;
	}
	fo(i,1,_)printf("%lld\n",(Ans[i]*f[a[i]])%mo);
	// cerr<<clock()-SRT<<endl;
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值