[51nod1847][算法马拉松23(飞越愚人节)F]奇怪的数学题

2 篇文章 0 订阅
2 篇文章 0 订阅

前言

万年不写公开博客了,这次填个坑

题目相关

链接

题目大意

∑ i = 1 N ∑ j = 1 N s g c d ( i , j ) k ( m o d 2 32 ) \sum_{i=1}^N\sum_{j=1}^Nsgcd(i,j)^k\pmod {2^{32}} i=1Nj=1Nsgcd(i,j)k(mod232)
sgcd(i,j)为i,j的第二大公约数
特殊的,若gcd(i,j)=1,则sgcd(i,j)=0

数据范围

n ≤ 1 0 9 , k ≤ 50 n\le10^9,k\le50 n109,k50

题解

设m(x)为x的次大因数,特殊的,m(1)=0
∑ i = 1 N ∑ j = 1 N s g c d ( i , j ) k = ∑ i = 1 N ∑ j = 1 N m ( g c d ( i , j ) ) k 根 据 定 义 = ∑ g = 1 N m ( g ) k ∑ i = 1 ⌊ N g ⌋ ∑ j = 1 ⌊ N g ⌋ [ g c d ( i , j ) = = 1 ] 提 出 g c d = ∑ g = 1 N m ( g ) k ( 2 ( ∑ i = 1 ⌊ N g ⌋ φ ( i ) ) − 1 ) 大 小 互 换 也 可 以 所 以 要 乘 以 2 , 并 且 ( 1 , 1 ) 只 能 算 一 次 所 以 减 一 = ∑ t = 1 n ∑ ⌊ N g ⌋ = t m ( g ) k ( 2 ( ∑ i = 1 t φ ( i ) ) − 1 ) \begin{aligned} \sum_{i=1}^N\sum_{j=1}^Nsgcd(i,j)^k&=\sum_{i=1}^N\sum_{j=1}^Nm(gcd(i,j))^k&根据定义\\ &=\sum_{g=1}^Nm(g)^k\sum_{i=1}^{\left\lfloor\frac{N}{g}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{N}{g}\right\rfloor}[gcd(i,j)==1]&提出gcd\\ &=\sum_{g=1}^Nm(g)^k\left(2\left(\sum_{i=1}^{\left\lfloor\frac{N}{g}\right\rfloor}\varphi(i)\right)-1\right)&大小互换也可以所以要乘以2,并且(1,1)只能算一次所以减一\\ &=\sum_{t=1}^n\sum_{\left\lfloor\frac{N}{g}\right\rfloor=t}m(g)^k\left(2\left(\sum_{i=1}^{t}\varphi(i)\right)-1\right)\\ \end{aligned} i=1Nj=1Nsgcd(i,j)k=i=1Nj=1Nm(gcd(i,j))k=g=1Nm(g)ki=1gNj=1gN[gcd(i,j)==1]=g=1Nm(g)k2i=1gNφ(i)1=t=1ngN=tm(g)k(2(i=1tφ(i))1)gcd2(1,1)
我们发现,满足条件的t只有 O ( n ) \mathcal O(\sqrt n ) O(n )个,而最后一项可以通过杜教筛来做
容易发现,对于同一个t,其满足条件的g是连续的一串,那么只要对于所有满足条件的t求 ∑ g = 1 m a x g m ( g ) k \sum_{g=1}^{maxg}m(g)^k g=1maxgm(g)k,这个用min_25筛算
因为本质上min25筛会枚举最小因数,所以把最小因数排除掉即可

在预处理上述运算的时候要求 ∑ g = 1 n g k \sum_{g=1}^{n}g^k g=1ngk
我们引入斯特林数
x n = ∑ i = 0 x { n i } x i ↓ x^n=\sum_{i=0}^x\begin{Bmatrix}n\\i\end{Bmatrix}x^{i\downarrow} xn=i=0x{ni}xi
证明可以点进那篇博客看
这样的话,求sigma就是
∑ x = 1 n x k = ∑ x = 1 n ∑ i = 0 x { k i } x i ↓ = ∑ i = 0 n { k i } ∑ x = i n x i ↓ = ∑ i = 0 n { k i } ∑ x = i n ( x i ) i ! = ∑ i = 0 n i ! { k i } ∑ x = i n ( x i ) = ∑ i = 0 n i ! { k i } ( n + 1 i + 1 ) = ∑ i = 0 n i ! { k i } ( n + 1 ) ! ( i + 1 ) ! ( n − i ) ! = ∑ i = 0 n { k i } ( n + 1 ) ! ( i + 1 ) ( n − i ) ! = ∑ i = 0 n { k i } ( n + 1 ) i + 1 ↓ i + 1 \begin{aligned} \sum_{x=1}^nx^k&=\sum_{x=1}^n\sum_{i=0}^x\begin{Bmatrix}k\\i\end{Bmatrix}x^{i\downarrow}\\ &=\sum_{i=0}^n\begin{Bmatrix}k\\i\end{Bmatrix}\sum_{x=i}^nx^{i\downarrow}\\ &=\sum_{i=0}^n\begin{Bmatrix}k\\i\end{Bmatrix}\sum_{x=i}^n\binom{x}{i}i!\\ &=\sum_{i=0}^ni!\begin{Bmatrix}k\\i\end{Bmatrix}\sum_{x=i}^n\binom{x}{i}\\ &=\sum_{i=0}^ni!\begin{Bmatrix}k\\i\end{Bmatrix}\binom{n+1}{i+1}\\ &=\sum_{i=0}^ni!\begin{Bmatrix}k\\i\end{Bmatrix}\frac{(n+1)!}{(i+1)!(n-i)!}\\ &=\sum_{i=0}^n\begin{Bmatrix}k\\i\end{Bmatrix}\frac{(n+1)!}{(i+1)(n-i)!}\\ &=\sum_{i=0}^n\begin{Bmatrix}k\\i\end{Bmatrix}\frac{(n+1)^{i+1\downarrow}}{i+1}\\ \end{aligned} x=1nxk=x=1ni=0x{ki}xi=i=0n{ki}x=inxi=i=0n{ki}x=in(ix)i!=i=0ni!{ki}x=in(ix)=i=0ni!{ki}(i+1n+1)=i=0ni!{ki}(i+1)!(ni)!(n+1)!=i=0n{ki}(i+1)(ni)!(n+1)!=i=0n{ki}i+1(n+1)i+1
此处复杂度 O ( k 2 ) \mathcal O(k^2) O(k2)
总复杂度 O ( n 3 4 l o g   n + n k 2 + n 2 3 ) \mathcal O(\frac{n^{\frac34}}{log\ n }+\sqrt nk^2+n^{\frac23}) O(log nn43+n k2+n32)

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define rg register
typedef long long LL;
typedef unsigned int ULL;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{
    char cu=getchar();x=0;bool fla=0;
    while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}
    while(isdigit(cu))x=x*10+cu-'0',cu=getchar();
    if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{
    if(x>=10)printe(x/10);
    putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{
    if(x<0)putchar('-'),printe(-x);
    else printe(x);
}
namespace du
{
	const int MAX=2000000;
	bool isprime[MAX+1];
	int n,prime[MAX+1],primesize;LL phi[MAX+1],phi1[MAX+1];
	inline void getlist(const LL listsize)
	{
		memset(isprime,1,sizeof(isprime));
		isprime[1]=0,phi[1]=1;;
		for(rg int i=2;i<=listsize;i++)
		{
			if(isprime[i])prime[++primesize]=i,phi[i]=i-1;
			for(rg int j=1;j<=primesize&&(LL)i*prime[j]<=listsize;j++)
			{
				isprime[i*prime[j]]=0;
				if(i%prime[j]==0)
				{
					phi[i*prime[j]]=phi[i]*prime[j];
					break;
				}
				phi[i*prime[j]]=phi[i]*(prime[j]-1);
			}
		}
	}
	inline LL Val(const int x)
	{
		if(x<=MAX)return phi[x];
		return phi1[n/x];
	}
	void pre(int ttt)
	{
		n=ttt;
		getlist(MAX);
		for(rg int i=1;i<=MAX;i++)phi[i]+=phi[i-1];
		for(rg int i=min((int)sqrt(n),n/(MAX+1));i>=1;i--)
		{
			const int u=n/i;
			LL res=(LL)u*(u+1)/2;
			int limit=sqrt(u);
			for(rg int j=1;j<=limit;j++)res-=Val(u/j);
			limit++;
			for(rg int j=1;limit*j<=u;j++)res-=phi[j]*((u/j)-(u/(j+1)));
			phi1[i]=res;
		}
	}
}
int n,k,part,tot,qz[700001],prime[700001],sq[700001],primesize,sum0[700001],id[700001];
inline int ck(const int x){return x<=part?x:tot-n/x+1;}
ULL S[51][51],sum2[700001],sum3[700001];
LL sum1[700001];
void pre()
{
	S[0][0]=1;
	for(rg int i=1;i<=k;i++)
		for(rg int j=1;j<=i;j++)
			S[i][j]=S[i-1][j-1]+j*S[i-1][j];
}
inline ULL qzktime(int x)
{
	ULL ans=0,dq=0;
	for(rg int i=0;i<=k;i++)
		for(rg int j=x-i+1;j<=x+1;j++)
			if(j%(i+1)==0)
			{
				dq=S[k][i];
				for(rg int l=x-i+1;l<=x+1;l++)
					if(j==l)dq*=l/(i+1);
					else dq*=l;
				ans+=dq;
				break;
			}
	return ans;
}
int val[700001];
ULL R[700001],ans,QZ[700001];
ULL pow(ULL x,int y)
{
	ULL res=1;
	for(;y;y>>=1,x=x*x)if(y&1)res*=x;
	return res;
}
int main()
{
	read(n),read(k);
	du::pre(n),pre();
    part=sqrt(n);
    tot=primesize=0;
    for(rg int i=1;i<=part;i++)id[++tot]=i,sum0[tot]=i-1,sum1[tot]=((((LL)i+1)*i)>>1)-1,sum2[tot]=qzktime(i)-1,sum3[tot]=i-1;
    id[++tot]=n/part;
    if(id[tot]!=part)sum0[tot]=id[tot]-1,sum1[tot]=((LL)(((LL)id[tot]+1)*id[tot])>>1)-1,sum2[tot]=qzktime(id[tot])-1,sum3[tot]=id[tot]-1;
    else tot--;
    for(rg int i=part-1;i>=1;i--)id[++tot]=n/i,sum0[tot]=id[tot]-1,sum1[tot]=((((LL)id[tot]+1)*id[tot])>>1)-1,sum2[tot]=qzktime(id[tot])-1,sum3[tot]=id[tot]-1;
    for(rg int i=2;i<=part;i++)
        if(sum0[i]!=sum0[i-1])
        {
            const int limit=i*i;
            ULL I=pow(i,k);
            for(rg int j=tot;id[j]>=limit;j--)
            {
                const int t=ck(id[j]/i);
                sum3[j]+=sum2[t]-QZ[primesize]-sum0[t]+primesize;
                sum2[j]-=(sum2[t]-QZ[primesize])*I;
                sum1[j]-=(sum1[t]-qz[primesize])*i;
                sum0[j]-=sum0[t]-primesize;
            }
            prime[++primesize]=i,sq[primesize]=i*i,qz[primesize]=qz[primesize-1]+i,QZ[primesize]=QZ[primesize-1]+I;
        }
    for(rg int i=1;i<=tot;i++)sum1[i]-=sum0[i];//printf("%lld\n",sum1[i]);//sum1为phi的前缀和
    for(rg int i=1;i<=part;i++)val[i]=n/i,R[i]=sum3[ck(val[i])];//printf("%d %u %lld\n",val[i],R[i],sum1[i]+1);
	for(rg int i=part+1;i<=tot;i++)val[i]=tot-i+1,R[i]=sum3[ck(val[i])];//printf("%d %u %lld\n",val[i],R[i],sum1[i]+1);
	for(rg int i=1;i<=part;i++)ans+=(R[i]-R[i+1])*(2*(ULL)du::Val(i)-1);//printf("%lld\n",sum1[i]);
	for(rg int i=part+1;i<=tot;i++)ans+=(R[i]-R[i+1])*(2*(ULL)du::Val(n/(tot-i+1))-1);
	print(ans),putchar('\n');
	return 0;
}

后记

本题可以用min_25而不用杜教筛
但我太菜了没有学过非递归min_25
QAQ

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值