【BZOJ3601】一个人的数论(数论)

【BZOJ3601】一个人的数论(数论)

题面

BZOJ
怎么这图片这么大啊。。。

题解

要求的是\(\displaystyle \sum_{i=1}^n [gcd(i,n)=1]i^d\)
然后把\(gcd=1\)给拆了,\(\displaystyle \sum_{i=1}^n i^d\sum_{x|i,x|n}\mu(x)\)
然后再把\(\mu\)丢掉前面去,\(\displaystyle \sum_{x|n}\mu(x)x^d\sum_{i=1}^{n/x}i^d\)
后面一半是自然数幂和,随便怎么搞都行。然而前面似乎就没法搞了QwQ。
首先自然数幂和可以写成一个多项式。
对于\(\sum_{i}i^d\)而言,一定可以写成一个\(d+1\)次多项式。
假装这个多项式的系数是\(a_i\)
那么式子就可以改写成:\(\displaystyle \sum_{k=0}^d a_k\sum_{x|n}\mu(x)x^d[\frac{n}{x}]^k\)
后面这个东西很明显就是三个积性函数乘起来的,所以后面这个东西也是一个积性函数。
而现在已经给定了\(n\)的分解情况,那么只需要对于每个质数求解贡献。
而每个质因子的出现次数超过\(1\)的时候贡献就是\(0\),所以只有出现\(0\)次或者\(1\)次的时候有贡献,那么后面这个东西似乎就很好算的样子啦。
现在的问题就回到了如何求解\(a_i\)上面。
这个东西可以待定系数+高斯消元直接爆算出解。
也可以拉格朗日插值直接算。

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 105
#define MOD 1000000007
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int ans,d,W,a[MAX],p[MAX],b[MAX],c[MAX],pro[MAX];
int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
void pre()
{
	for(int i=1;i<=d+2;++i)p[i]=(p[i-1]+fpow(i,d))%MOD;b[0]=1;
	for(int i=0;i<=d+1;++i)
	{
		for(int j=i+1;j;--j)b[j]=(b[j-1]+MOD-1ll*b[j]*(i+1)%MOD)%MOD;
		b[0]=1ll*b[0]*(MOD-i-1)%MOD;
	}
	for(int i=0;i<=d+1;++i)
	{
		int s=p[i+1],inv=fpow(i+1,MOD-2);
		for(int j=0;j<=d+1;++j)if(i!=j)s=1ll*s*fpow((i-j+MOD)%MOD,MOD-2)%MOD;
		b[0]=1ll*b[0]*(MOD-inv)%MOD;
		for(int j=1;j<=d+2;++j)b[j]=(MOD-1ll*(b[j]+MOD-b[j-1])*inv%MOD)%MOD;
		for(int j=0;j<=d+2;++j)a[j]=(a[j]+1ll*s*b[j])%MOD;
		for(int j=d+2;j;--j)b[j]=(b[j-1]+MOD-1ll*b[j]*(i+1)%MOD)%MOD;
		b[0]=1ll*b[0]*(MOD-i-1)%MOD;
	}
}
int main()
{
	d=read();W=read();pre();
	for(int i=0;i<=d+1;++i)pro[i]=1;
	while(W--)
	{
		int p=read(),v=read(),n=fpow(p,v),inv=fpow(p,MOD-2),pd=fpow(p,d);
		for(int k=0;k<=d+1;++k)
		{
			int ret=(fpow(n,k)+MOD-1ll*pd*fpow(1ll*n*inv%MOD,k)%MOD)%MOD;
			pro[k]=1ll*pro[k]*ret%MOD;
		}
	}
	for(int i=0;i<=d+1;++i)ans=(ans+1ll*a[i]*pro[i])%MOD;
	printf("%d\n",ans);
	return 0;
}
posted @ 2019-03-09 21:35  小蒟蒻yyb  阅读(878)  评论(0编辑  收藏  举报