QOJ1285 Stirling Number
因为 ,所以设 ,其中 ,则有:
设 ,其中 ,那么:
设 ,其中 ,那么:
又因为:
这个式子由 易证。
那么:
那么剩下的问题是给定 ,求 的前 次项系数和。
考虑一个多项式 ,设模数的原根为 ,若我们求出 ,那么我们可以线性地求出 的前 次项系数和。
具体地,考虑 ,只有当 时这个式子等于 ,当 时由等比数列求和公式可知它等于 。
那么考虑若要求 的第 次项, 即为答案。
所以:
求 可以预处理阶乘及其逆元然后 单次计算,后面那个 可以用等比数列求和公式然后预处理原根的次方做到 单次计算。
总时间复杂度 。
code
#include <bits/stdc++.h> #define pb emplace_back #define fst first #define scd second #define mkp make_pair #define mems(a, x) memset((a), (x), sizeof(a)) using namespace std; typedef long long ll; typedef double db; typedef unsigned long long ull; typedef long double ldb; typedef pair<ll, ll> pii; const int maxn = 1000100; ll n, L, R, P, fac[maxn], ifac[maxn], N, G, q, r, inv[maxn], pw[maxn]; inline ll qpow(ll b, ll p) { ll res = 1; while (p) { if (p & 1) { res = res * b % P; } b = b * b % P; p >>= 1; } return res; } inline ll C(ll n, ll m) { if (n < m || n < 0 || m < 0) { return 0; } if (n >= P) { return C(n / P, m / P) * C(n % P, m % P) % P; } else { return fac[n] * ifac[m] % P * ifac[n - m] % P; } } inline bool check(ll x) { ll t = P - 1; vector<ll> vc; for (ll i = 2; i * i <= t; ++i) { if (t % i == 0) { vc.pb(i); while (t % i == 0) { t /= i; } } } if (t > 1) { vc.pb(t); } for (ll y : vc) { if (qpow(x, (P - 1) / y) == 1) { return 0; } } return 1; } inline ll g(ll n, ll m) { ll p = 1, ip = 1, iG = qpow(G, P - 2), res = 0; for (int i = 0; i <= P - 2; ++i, p = p * G % P, ip = ip * iG % P) { if (p + n - 1 >= P) { continue; } if (ip == 1) { res = (res + (m + 1) * fac[p + n - 1] % P * ifac[p - 1]) % P; } else { res = (res + (pw[((-(m + 1) * i) % (P - 1) + P - 1) % (P - 1)] + P - 1) % P * inv[(ip + P - 1) % P] % P * fac[p + n - 1] % P * ifac[p - 1]) % P; } } return (P - res) % P; } inline ll h(ll m) { if (m < q) { return 0; } ll k = (m - q) / (P - 1); ll t = (m - q) % (P - 1); ll ans = C(q, k) * g(r, t) % P; ans = (ans - C(q - 1, k - 1) * fac[r] % P + P) % P; if ((q - k) & 1) { ans = (P - ans) % P; } return ans; } void solve() { scanf("%lld%lld%lld%lld", &n, &L, &R, &P); N = P - 1; fac[0] = 1; for (int i = 1; i <= N; ++i) { fac[i] = fac[i - 1] * i % P; } ifac[N] = qpow(fac[N], P - 2); for (int i = N - 1; ~i; --i) { ifac[i] = ifac[i + 1] * (i + 1) % P; } inv[1] = 1; for (int i = 2; i <= N; ++i) { inv[i] = (P - P / i) * inv[P % i] % P; } for (G = 1;; ++G) { if (check(G)) { break; } } pw[0] = 1; for (int i = 1; i <= P - 2; ++i) { pw[i] = pw[i - 1] * G % P; } q = n / P; r = n - P * q; printf("%lld\n", (h(R) - h(L - 1) + P) % P); } int main() { int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库