【题解】Zoj3547 The Boss on Mars

这道题题意很简单,就是每次给你一个 n,让你求所有小于 n 且与 n 互质的数的四次方之和。

好吧,这题看着好像不是很难耶。。。然后我就看到了 n<=10 8 ^8 8,t<=100。。。怎么还是多组数据啊QwQ

那这道题该怎么解呢?首先肯定有很多同学想到了一个东西:分解质因数。但是看上去好像又没什么卵用,因为当 n 是一个质数的时候,小于它的所有数都与它互质,你的复杂度一点没变。

那么我们还可以想到一个方法:你先算出所有数的 n 次方之和,然后减去与它不互质的数的四次方之和不就行了吗?嗯,这个方法看上去是可行的。。。

现在我们就把问题划分成了两部分:快速求出 1~n 的四次方之和与如何快速求出与它不互质的数的四次方之和。显然,第二部分可以在分解质因数后直接用容斥去求,容斥不会的自行去补(逃)。

那么四次方和怎么求呢?其实四次方和是有公式的,没有兴趣看证明的同学可以省掉下面一坨证明:

1 4 ^4 4+2 4 ^4 4+…+n 4 ^4 4=n(n+1)(2n+1)(3n 2 ^2 2+3n-1)/30

下面是为喜欢数学的同学量身打造的证明:


我们先来看一下1 2 ^2 2+2 2 ^2 2+…+n 2 ^2 2的证明:

n 3 ^3 3-(n-1) 3 ^3 3=3n 2 ^2 2-3n+1

(n-1) 3 ^3 3-(n-2) 3 ^3 3=3(n-1) 2 ^2 2-3(n-1)+1

1 3 ^3 3-0 3 ^3 3=3·1 2 ^2 2-3·1+1

让我们把这些式子加起来,就会得到一个长式子:

n 3 ^3 3-(n-1) 3 ^3 3+(n-1) 3 ^3 3-(n-2) 3 ^3 3+…+2 3 ^3 3-1 3 ^3 3=3·Σ(i 2 ^2 2)-3·Σi+n

整理得:n 3 ^3 3-1=3(1 2 ^2 2+2 2 ^2 2+…+n 2 ^2 2)+3(1+2+…+n)-n

这时候只需要移项不就可以求出 1 2 ^2 2+2 2 ^2 2+…+n 2 ^2 2 的值了吗?

同样的,1 4 ^4 4+2 4 ^4 4+…+n 4 ^4 4 也可以用此方法来求,具体步骤初中数学水平应该就可以完成,我就不再多说了。

#include<iostream>
#include<stdio.h>
#include<map>
#include<vector>
#include<string.h>
#define mod 1000000007
#define dmod 233333335 //30模1e9+7的逆元
using namespace std;
int n;
vector<int> q;//保存 n 的质因数集合
void shuffle(int N)//分解质因数
{
	int LN=N;
	for(int i=2;i*i<=LN;i++)
	{
		if(N==1)	break;
		if(N%i)	continue;
		q.push_back(i);
		while(N%i==0)	N/=i;
	}
	if(N!=1)
		q.push_back(N);
}
long long getsum(long long x) {return x*(x+1)%mod*(x*2+1)%mod*(x*3%mod+x*x%mod*3%mod-1)%mod*dmod%mod;}//getsum(n)=pow(1,4)+pow(2,4)+...+pow(n,4)
long long cal(long long x) {return (getsum(n/x)*x%mod*x%mod*x%mod*x%mod)%mod;}//容斥中当前因数为x时的值
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		q.clear();
		scanf("%d",&n);
		shuffle(n);
		if(n==1)
			{cout<<"0\n"; continue;}//这个特判非常重要!
		int N=q.size();
		long long ans=getsum(n);
		for(int i=1;i<(1<<N);i++)//枚举质因子集合
		{
			long long now=1;int num=0;
			for(int j=0;j<N;j++)
				if(i&(1<<j))
					now*=q[j],num++;	//计算质因子积和当前用了几个质因子
			if(!num)	continue;
			if((num&1)==0)	ans=(ans+cal(now))%mod;
			else	ans=(ans-cal(now)+mod)%mod;//标准容斥
		}
		printf("%lld\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值