【BZOJ3601】一个人的数论

题目链接

题意简述

求小于 n 且与 n 互质的数的 k 次方之和。

Sol

要求的东西:

∑ i = 1 n i k [ g c d ( i , n ) = 1 ] \sum_{i=1}^n i^k [gcd(i,n)=1] i=1nik[gcd(i,n)=1]
枚举 gcd 上个莫比乌斯函数:
∑ i = 1 n i k ∑ d ∣ n , d ∣ i μ ( d ) \sum_{i=1}^n i^k \sum_{d|n,d|i} \mu(d) i=1nikdn,diμ(d)
交换求和顺序
∑ d ∣ n μ ( d ) ∑ i = 1 n d ( i d ) k \sum_{d|n} \mu(d) \sum_{i=1}^{\frac{n}{d}} (id)^k dnμ(d)i=1dn(id)k
这样就差不多没有办法继续了:
∑ d ∣ n μ ( d ) ∗ d k ∑ i = 1 n d i k \sum_{d|n} \mu(d)*d^k \sum_{i=1}^{\frac{n}{d}} i^k dnμ(d)dki=1dnik

题目中给出的是 n 的分解式 , 这使得我们往积性函数上想。

发现前面的 μ ( d ) \mu(d) μ(d) 是积性函数 , d k d^k dk 是个完全积性函数,那么就只剩下最后那个东西了。

这就是个自然质数幂嘛,它是个关于 x = n d x=\frac{n}{d} x=dn k + 1 k+1 k+1次多项式,这样子我们可以把这个多项式的系数直接高斯消元或着拉格朗日插值给弄出来,假设系数是 a i a_i ai ,那么就是:
∑ d ∣ n μ ( d ) ∗ d k ∑ i = 0 k + 1 a i ( n d ) i \sum_{d|n} \mu(d)*d^k \sum_{i=0}^{k+1} a_i\bigg(\frac{n}{d}\bigg)^i dnμ(d)dki=0k+1ai(dn)i
交换个求和顺序就好了:

∑ i = 0 k + 1 a i ∑ d ∣ n μ ( d ) ∗ d k ( n d ) i \sum_{i=0}^{k+1}a_i\sum_{d|n} \mu(d)*d^k \bigg(\frac{n}{d}\bigg)^i i=0k+1aidnμ(d)dk(dn)i

后面就是个狄利克雷卷积,它也是个积性函数了,直接计算好 n n n p k p^k pk 时的结果乘起来就好了,因为莫比乌斯函数必须是在无平方因子时才不为 0 0 0,所以 d d d 只有 1 1 1 p p p 两种取值,直接算就行了。

code:

#include<bits/stdc++.h>
using namespace std;
template<class T>inline void init(T&x){
	x=0;char ch=getchar();bool t=0;
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
	if(t) x=-x;return;
}
typedef long long ll;
const int mod=1e9+7,phi=mod-1;
template<class T>inline void Inc(T&x,int y){x+=y;if(x>=mod) x-=mod;return;}
template<class T>inline void Dec(T&x,int y){x-=y;if(x < 0 ) x+=mod;return;}
template<class T>inline int fpow(int x,T k){int ret=1;for(;k;k>>=1,x=(ll)x*x%mod)if(k&1) ret=(ll)ret*x%mod;return ret;}
inline int Sum(int x,int y){x+=y;return x>=mod? (x-mod):x;}
inline int Dif(int x,int y){x-=y;return x < 0 ? (x+mod):x;}
const int N=1021;
int d,w;
namespace Lagerange{
	int coef[N],Y[N];
	typedef vector<int> Poly;
	inline Poly Mul(Poly A,Poly B){
		Poly Res;int szl=A.size(),szr=B.size();Res.resize(szl+szr-1);
		for(int i=0;i<szl;++i) for(int j=0;j<szr;++j) Inc(Res[i+j],(ll)A[i]*B[j]%mod);
		return Res;
	}
	Poly Divide(int l,int r,int I){
		if(l==r) {
			int len=r-l+1;Poly Res;Res.resize(len+1);
			if(l==I) Res[0]=1;
			else {int inv=fpow(Dif(I,l),mod-2);Res[0]=(ll)(mod-l)*inv%mod;Res[1]=inv;}
			return Res;
		}
		int mid=l+r>>1;Poly A=Divide(l,mid,I),B=Divide(mid+1,r,I);
		return Mul(A,B);
	}
	inline void Solve(int K){
		int LIM=K+2;Y[0]=0;
		for(int i=1;i<=LIM;++i) Y[i]=Sum(Y[i-1],fpow(i,K));
		for(int i=1;i<=LIM;++i) {
			Poly ret=Divide(1,LIM,i);
			int sz=ret.size();
			for(int j=0;j<sz;++j) Inc(coef[j],(ll)Y[i]*ret[j]%mod);
		}
		return;
	}
}using Lagerange::coef;
int P[N],alpha[N];
inline int Calc(int i){
	int ret=1;
	for(int j=1;j<=w;++j) ret=(ll)ret*Dif(fpow(P[j],(ll)alpha[j]*i%phi),fpow(P[j],((ll)(alpha[j]-1)*i%phi+d)%phi))%mod;
	return ret;
}
int main()
{
	init(d),init(w);
	Lagerange::Solve(d);
	int ans=0;
	for(int i=1;i<=w;++i) init(P[i]),init(alpha[i]);
	for(int i=0;i<=d+1;++i) Inc(ans,(ll)coef[i]*Calc(i)%mod);
	cout<<ans<<endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值