1. 程式人生 > 其它 >P6271 [湖北省隊互測2014]一個人的數論

P6271 [湖北省隊互測2014]一個人的數論

\(\text{Solution}\)

題目大意是求

\[\sum_{i = 1}^n [i \perp n]i^k \]

簡單的推一波柿子

\[=\sum_{i = 1}^n\sum_{d|gcd(i,n)}\mu(d)i^k \] \[=\sum_{d|n}\mu(d)d^k\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}i^k \]

這不是自然數冪和嗎?拉格朗日插出多項式係數\(a_i\),所以可以換一種表示方式

\[=\sum_{d|n}\mu(d)d^k\sum_{i = 0}^{k+1}a_i(\lfloor\frac{n}{d}\rfloor)^i \] \[=\sum_{i = 0}^{k + 1}a_in^i\sum_{d|n}\mu(d)d^{k-i} \]

注意到\(\mu(d)d^k\)

是積性函式

\[=\sum_{i = 0}^{k + 1}a_in^i\prod_{j = 1}^w(1 - p_j^{k-i}) \]

到這就隨便做了

\(\text{Code}\)

#include<cstdio>
#define LL long long
using namespace std;
const int P = 1e9 + 7,N = 1e3 + 5;
int k,w; LL p[N],pm[N][105],g[105],S[105],A[105];

LL fpow(LL x,LL y)
{
	LL res = 1;
	for (; x; x >>= 1,y = y * y % P)
		if (x & 1) res = res * y % P;
	return res;
}
int main()
{
	scanf("%d%d",&k,&w); LL n = 1;
	for (int i = 1,q; i <= w; i++) 
		scanf("%lld%d",&p[i],&q),pm[i][1] = 1,pm[i][0] = fpow(P - 2,p[i]),n = n * fpow(q,p[i]) % P;
	for (int i = 1; i <= w; i++)
		for (int j = 2; j <= k + 1; j++) pm[i][j] = (LL)pm[i][j - 1] * p[i] % P;
	for (int i = 1; i <= k + 2; i++) g[i] = (g[i - 1] + fpow(k,i)) % P;
	S[0] = P - 1,S[1] = 1;
	for (int i = 2; i <= k + 2; i++)
	{
		for (int j = i; j >= 1; j--) S[j] = (S[j - 1] - (LL)S[j] * i % P + P) % P;
		S[0] = (P - S[0] * i % P) % P;
	}
	for (int i = 1; i <= k + 2; i++)
	{
		LL C = 1,sc = S[k + 2];
		for (int j = 1; j <= k + 2; j++)
			if (i != j) C = C * (i - j + P) % P;
		C = g[i] * fpow(P - 2,C) % P;
		for (int j = k + 1; j >= 0; j--)
			A[j] = (A[j] + C * sc % P) % P,sc = (S[j] + sc * i % P + P) % P;
	}
	LL ans = 0,sn = 1;
	for (int i = 0; i <= k + 1; i++)
	{
		LL res = 1;
		for (int j = 1; j <= w; j++) res = res * (P + 1 - pm[j][k - i + 1]) % P;
		ans = (ans + A[i] * sn % P * res % P) % P,sn = sn * n % P;
	}
	printf("%lld\n",ans);
}