:::info[Description] Link. :::
:::infoSolution 首先有经典结论 ,因此当 时必有 , 就都可以被简单的表示出来。
然后可以发现 都是 的幂次的形式(这里认为 是任何数的幂次),因此 区间可以被分割成若干个长度为 的完整段,每种模 的余数都恰好出现 次,其中 是区间的长度即 。问题变成:有 个余数 ,选一些数,使得余数的和在 意义下为 。
看到 容易想到单位根反演,记 为 次单位根,则答案可以被表示为:。记 ,则问题就在于计算 的值。
记 ,则 的阶就是 。令 ,因为 的阶是 ,因此 就恰好是全部的 次单位根。当 从 走到 时, 会把这 个单位根重复 遍,因此显然有 。记 ,则只需要计算所有的 的值即可。
有经典结论 ,代入 可得 。
因此可以计算出 的值:若 为奇数,则 ,否则 。反推可得若 为奇数则有 ,否则有 。
最后考虑所有 次单位根中,阶恰好为 的单位根恰好有 个。因此可以考虑把所有的 按照其阶 的值来合并,即答案为 。
具体实现过直接线性筛出 函数的值然后每组询问枚举 的所有奇数因数 算出 的值即可。总时间复杂度为 ,可以通过该题。注意幂的指数要对 取模而不是对 取模。 :::
:::success[Code]
namespace lowspeed_song {
int phi[N], pr[N], isp[N], idx;
inline void init() {
isp[1] = phi[1] = 1;
for (int i = 2; i < N; ++i) {
if (!isp[i]) pr[++idx] = i, phi[i] = i - 1;
for (int j = 1; j <= idx && i * pr[j] < N; ++j) {
isp[i * pr[j]] = 1;
if (i % pr[j] == 0) { phi[i * pr[j]] = phi[i] * pr[j]; break; }
phi[i * pr[j]] = phi[i] * (pr[j] - 1);
}
}
}
inline void sol() {
int m, a, b, c, d; cin >> m >> a >> b >> c >> d;
int res = 0, L = 1, R = 1;
if (a && b) {
int g = gcd(a, b);
for (int i = 0; i < g; ++i) L *= m;
++L;
} else L = 1;
if (c && d) {
int g = gcd(c, d);
for (int i = 0; i < g; ++i) R *= m;
} else R = 0;
if (L >= R) { cout << 1 << '\n'; return; }
int n = R - L + 1;
// cout << L << ' ' << R << '\n';
for (int i = 1; i * i <= m; ++i) {
if (m % i == 0) {
if (i & 1) res = (res + power(2, n / i, mod) * phi[i] % mod) % mod;
if (i * i != m && (m / i) % 2) res = (res + power(2, n / (m / i), mod) * phi[m / i] % mod) % mod;
}
}
cout << res * inversion(m) % mod << '\n';
}
} // namespace lowspeed_song:::
难度:黑
鲜活指数:5
喜欢的话,留下你的评论吧~