题解 P6271 【[湖北省队互测2014]一个人的数论】
一道经典的莫比乌斯反演练习题。
这里规定一下变量名:
题目中的
题目中的
题目中的
考虑构造:
则我们最后想要的答案为
不难发现有:
那么我们考虑对其做莫比乌斯反演,则有:
注意到
那么对上面的式子展开即得:
若
注意到
所以最后一个
而我们想要的就是
这个东西的一般暴力方法可以用拉格朗日插值做到
对于一个
然后纯粹模拟多项式乘法和多项式加法,就可以做到
至此,整个问题就可以在
部分代码如下:
const int mod = 1e9 + 7;
inline int Mod(int x) { return x >= mod ? x - mod : x; }
inline void Add(int &x, int y) { x += y, x -= x >= mod ? mod : 0; }
inline int fsp(int x, int k = mod - 2) {
int s = 1;
while(k) {
if(k & 1) s = 1LL * s * x % mod;
x = 1LL * x * x % mod, k >>= 1;
} return s;
}
int f[110];
int p[1010];
// {{{ Lagrange
int A[110];
int len;
inline void Poly_Mul(int a, int b) {
++len;
for(int i = len; i >= 1; i--)
A[i] = (1LL * A[i] * b + 1LL * A[i - 1] * a) % mod;
A[0] = 1LL * A[0] * b % mod;
}
inline void Num_Mul(int v) {
for(int i = 0; i <= len; i++)
A[i] = 1LL * A[i] * v % mod;
}
inline void Poly_Add() {
for(int i = 0; i <= len; i++)
Add(f[i], A[i]), A[i] = 0;
len = 0, A[0] = 1;
}
inline void init(int k) {
A[0] = 1, len = 0;
int S = 0;
for(int i = 1; i <= k + 3; i++) {
Add(S, fsp(i, k));
int mul = fsp(S);
for(int j = 1; j <= k + 3; j++) {
if(i == j) continue;
Poly_Mul(1, mod - j);
mul = 1LL * mul * (i + mod - j) % mod;
} Num_Mul(fsp(mul)), Poly_Add();
}
}
// }}}
int main() {
int k = ri, n = ri, N = 1;
for(int i = 1; i <= n; i++) p[i] = ri, N = 1LL * N * fsp(p[i], ri) % mod;
init(k);
int res = 0, pw = N;
for(int i = 1; i <= k + 3; i++) {
int ans = 1LL * pw * f[i] % mod;
pw = 1LL * pw * N % mod;
for(int j = 1; j <= n; j++)
ans = 1LL * ans * (1 + mod - fsp(p[j], k - i + mod - 1)) % mod;
Add(res, ans);
} cout << res << endl;
return 0;
}