Live2D

题解 一个人的数论

题目传送门

Description

给出

\[n=\prod_{i=1}^{w}p_i^{a_i} \]

求出:

\[\sum_{i=1}^{n}[\gcd(i,n)=1]i^d \]

\(d\le 10^2,w\le 10^3\),答案对 \(10^9+7\) 取模。

Solution

\[\sum_{i=1}^{n} [\gcd(i,n)=1]i^d \]

\[=\sum_{i=1}^{n} (\sum_{k|i\wedge k|n}\mu(k))i^d \]

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

对于后面那一坨我们知道可以写成:

\[\sum_{i=1}^{d+1} f_i(\frac{n}{k})^i \]

所以原式可以写成:

\[=\sum_{k|n}\mu(k)k^d\sum_{i=1}^{d+1}f_i(\frac{n}{k})^i \]

\[=\sum_{i=1}^{d+1}f_in^i\sum_{k|n}\mu(k)k^{d-i} \]

我们可以观察到后面那一坨因为含有 \(\mu(k)\),所以所有能够产生贡献的 \(k\) 的指数最大值不会超过 \(1\),所以直接 dp 即可。

时间复杂度为 \(\Theta(d^3+dw)\)

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define mod 1000000007
#define MAXN 1005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

int k,n,p[MAXN],a[MAXN],f[MAXN];
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
	if (b < 0) b += mod - 1;
	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
	return res;
}
int inv (int x){return qkpow (x,mod - 2);}

int y[MAXN],mat[MAXN][MAXN];

void Gauss  (){
	int up = k + 1;
	for (Int i = 1;i <= up;++ i){
		for (Int j = 1;j <= up;++ j) mat[i][j] = qkpow (i,j); 
		for (Int j = 1;j <= i;++ j) mat[i][up + 1] = add (mat[i][up + 1],qkpow (j,k));
	}
	for (Int i = 1;i <= up;++ i){
		int pos = i;
		for (Int j = i + 1;j <= up;++ j) if (mat[j][i] > mat[pos][i]) pos = j;
		if (pos ^ i) swap (mat[i],mat[pos]);
		for (Int j = i + 1;j <= up;++ j){
			int det = mul (mat[j][i],inv (mat[i][i]));
			for (Int k1 = i;k1 <= up + 1;++ k1) mat[j][k1] = dec (mat[j][k1],mul (det,mat[i][k1]));
		}
	}
	for (Int i = up;i >= 1;-- i){
		for (Int j = up;j > i;-- j) mat[i][up + 1] = dec (mat[i][up + 1],mul (f[j],mat[i][j]));
		f[i] = mul (mat[i][up + 1],inv (mat[i][i]));
	}
} 

int getans (int i,int now){
	if (now > n) return 1;
	return mul (dec (1,qkpow (p[now],k - i)),getans (i,now + 1));
}

signed main(){
	read (k,n),Gauss ();
	int get = 1;
	for (Int i = 1;i <= n;++ i) read (p[i],a[i]),get = mul (get,qkpow (p[i],a[i]));
	int ans = 0;for (Int i = 1;i <= k + 1;++ i) ans = add (ans,mul (f[i],mul (qkpow (get,i),getans (i,1))));
	write (ans),putchar ('\n');
	return 0;
}
posted @ 2021-02-01 10:00  Dark_Romance  阅读(68)  评论(0编辑  收藏  举报