题解 P6266 【一个人的数论】

皎月半洒花

2020-04-01 20:45:27

Solution

upd: typo了一个地方,感谢NaCly_Fish的指正。 ____ 首先写出式子来 ![](https://cdn.luogu.com.cn/upload/image_hosting/6577i0r6.png) 然后发现这东西好像不是容易提前预处理。根据伯努利数的推论,可以知道 $\sum i^m$ 这东西是一个关于上界 $n$ 的 $m+1$ 次多项式。发现 $m$ 并不大于是可以 $O(m^2)$ 插出来。 若记这个多项式是 $f$ ,那么原式就等价于 $$\sum_{d|n}d^m\mu(d)\sum_{i=1}^{m+1} f_i\left(\lfloor\frac{n}{d}\rfloor\right) ^ i$$ 稍微化一下就是 $$=\sum_{i=0}^{m+1} f_{i} \sum_{d | n} d^{m} \mu(d)\left(\frac{n}{d}\right)^{i}$$ 发现对于后面的 $\sum $ 只需要求出每个 $p_i^{a_i}$ 处的值,然后每次 $O(k)$ 暴力合并,似乎也没啥问题。考虑对于每个 $p_i^{a_{i}}$ 怎么求。 这个地方大概需要涨个经验,就是要考虑 $\mu(d)$ 这东西的容斥意义,只有当 $d=1$ 和 $d=p_i$ 的时候才有值(无平方因子,剩下的因子都是 $p_i$ 的某个次数 $>2$ 的幂),所以每个只需要算两次,是 $O(1)$ 的。于是最后的复杂度 $O(m(m+k))$ 。 并且……这个题居然允许用高斯消元来代替插值。毕竟 $m$ 只有 $100$ 。 ```cpp #include <bits/stdc++.h> using namespace std ; typedef long long ll ; const int N = 1000010 ; const int P = 1000000007 ; int n, k ; void debug(int *tp, int minn, int maxn, char c){ for (int i = minn ; i <= maxn ; ++ i) cout << tp[i] << " " ; cout << c ; } namespace Interpolation{ int ans ; int now ; int x[N] ; int y[N] ; int fac[N] ; int inv[N] ; int pres[N] ; int sufs[N] ; int expow(int a, int b){ int res = 1 ; a = (a % P + P) % P ; while (b){ if (b & 1) res = (ll)res * a % P ; a = (ll)a * a % P ; b >>= 1 ; } return res ; } int fz[N] ; int fm[N] ; int tmp[N] ; int res[N] ; void add(int &a, int b){ a += b ; if (a > P) a -= P ; } void dec(int &a, int b){ (a -= b) %= P ; if (a < 0) a += P ; } void fmul(int *t, int deg, int opt){ for (int i = deg + 1 ; i >= 1 ; -- i) tmp[i] = t[i], t[i] = t[i - 1] ; for (int i = 1 ; i <= deg + 1 ; ++ i) add(t[i], (ll)opt * tmp[i] % P) ; } void fdiv(int *t, int *ret, int deg, int opt){ for (int i = 1 ; i <= deg ; ++ i) tmp[i] = t[i] ; for (int i = deg - 1 ; i >= 1 ; -- i) ret[i] = tmp[i + 1], dec(tmp[i], (ll)tmp[i + 1] * opt % P) ; } void get_xs(int n){ fz[1] = 1 ; for (int i = 1 ; i <= n ; ++ i) fmul(fz, i, (-x[i] + P) % P) ; //debug(fz, 1, n + 1, '\n') ; for (int i = 1 ; i <= n ; ++ i){ int fenmu = 1 ; for (int j = 1 ; j <= n ; ++ j) if (i != j) fenmu = (ll)fenmu * (x[i] - x[j] + P) % P ; fdiv(fz, fm, n + 1, -x[i]) ; fenmu = (ll)y[i] * expow(fenmu, P - 2) % P ; // cout << fenmu << endl ; for (int j = 1 ; j <= n ; ++ j) add(res[j], (ll)fenmu * fm[j] % P) ; // debug(res, 1, n, '\n') ; } } void pre_do(int U){ fac[0] = 1 ; for (int i = 1 ; i <= U ; ++ i) fac[i] = (ll)fac[i - 1] * i % P ; inv[U] = expow(fac[U], P - 2) ; for (int i = U ; i >= 1 ; -- i) inv[i - 1] = (ll)inv[i] * i % P ; //debug(fac, 1, U, '\n') ; //debug(inv, 1, U, '\n') ; } int evenmark(int x){ return (x & 1) ? -1 : 1 ; } void get_dnx(int n, int k, bool m){ if (m){ pre_do(n) ; pres[0] = 1, sufs[n + 1] = 1 ; for (int i = 1 ; i <= n ; ++ i) pres[i] = ((ll)pres[i - 1] * (k - x[i]) % P + P) % P ; for (int i = n ; i >= 1 ; -- i) sufs[i] = ((ll)sufs[i + 1] * (k - x[i]) % P + P) % P ; for (int i = 1 ; i <= n ; ++ i){ now = (ll)pres[i - 1] * sufs[i + 1] % P ; now = (ll)now * expow((ll)fac[i - 1] * fac[n - i] % P, P - 2) % P ; now = (ll)evenmark(n - i) * y[i] % P * now % P ; ans = (ll)(ans + now) % P ; } } else { int inow = 1 ; pres[0] = 1, sufs[n + 1] = 1 ; for (int i = 1 ; i <= n ; ++ i) pres[i] = ((ll)pres[i - 1] * (k - x[i]) % P + P) % P ; for (int i = n ; i >= 1 ; -- i) sufs[i] = ((ll)sufs[i + 1] * (k - x[i]) % P + P) % P ; for (int i = 1 ; i <= n ; ++ i){ inow = 1, now = (ll)pres[i - 1] * sufs[i + 1] % P ; for (int j = 1 ; j <= n ; ++ j) if (i != j) inow = (ll)inow * ((x[i] - x[j]) % P + P) % P ; ans = (ans + (ll)now * expow(inow, P - 2) % P * y[i] % P) % P ; } } } }/* namespace Linear_sieve{ int cnt ; int pr[N] ; int mu[N] ; int vis[N] ; void sieve(int U){ mu[1] = 1 ; for (int i = 2 ; i <= U ; ++ i){ if (!vis[i]) mu[i] = -1, pr[++ cnt] = i ; for (int j = 1 ; j <= cnt ; ++ j){ if (i * pr[j] > U) break ; vis[i * pr[j]] = 1 ; if (i % pr[j] == 0) break ; mu[i * pr[j]] = -mu[i] ; } } } }*/ int d, w, num ; int base[N], cs[N] ; int main(){ cin >> d >> w ; n = d + 2 ; // using namespace Linear_sieve ; using namespace Interpolation ; for (int i = 1 ; i <= n ; ++ i) x[i] = i, y[i] = (y[i - 1] + expow(x[i], d)) % P ; for (int i = 1 ; i <= w ; ++ i) cin >> base[i] >> cs[i] ; get_xs(n) ; // debug(y, 1, n + 1, '\n') ; // debug(res, 1, n + 1, '\n') ; for (int i = 1 ; i <= n + 1 ; ++ i){ now = 0, num = 1 ; for (int j = 1 ; j <= w ; ++ j){ now = expow(expow(base[j], cs[j] - 1), i - 1) ; now = ((-1ll * now * expow(base[j], d) % P) + P) % P ; now = (now + expow(expow(base[j], cs[j]), i - 1)) % P ; num = 1ll * num * now % P ; } ans = (ans + (ll)num * res[i] % P) % P ; } cout << ans << '\n' ; return 0 ; } ```