loj #6216. 雪花挂饰

时间:2024-01-01 23:08:27

(今天碰到的题怎么这么小清新

$n$ 个不相同的点,$q$ 组询问,每次给定 $l,r$,问在 $n$ 个点中,选出 $x$ 个点 $(x \in [l,r])$,用边连起来,能构成多少种不同的树

$n,q \leq 10^6$

sol:

首先知道 $n$ 个点的树有 $n^{n-2}$ 个,因为这题标号不同就算不同,所以 $i$ 个点不同的树有 $C_n^i \times i^{i-2}$

维护一下这东西的前缀和就可以每组询问 $O(1)$ 了

#include <bits/stdc++.h>
#define LL long long
using namespace std;
#define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
inline int read() {
int x = , f = ;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-')
f = -f;
for (; isdigit(ch); ch = getchar()) x = * x + ch - '';
return x * f;
}
const int maxn = 1e6 + ;
int n, T, mod, num[maxn], fac[maxn], ifac[maxn], cn[maxn], sum[maxn];
inline int ksm(int x, int t) {
if (t < )
return ;
if (t == )
return ;
int res = ;
for (; t; x = 1LL * x * x % mod, t = t >> )
if (t & )
res = 1LL * x * res % mod;
return res;
}
int main() {
n = read(), T = read(), mod = read();
rep(i, , n) num[i] = ksm(i, i - );
ifac[] = fac[] = ;
rep(i, , n) fac[i] = 1LL * fac[i - ] * i % mod;
ifac[n] = ksm(fac[n], mod - );
dwn(i, n - , ) ifac[i] = 1LL * ifac[i + ] * (i + ) % mod;
rep(i, , n) cn[i] = 1LL * (1LL * fac[n] * ifac[n - i] % mod) * ifac[i] % mod;
rep(i, , n) sum[i] = (sum[i - ] + (1LL * cn[i] * num[i] % mod)) % mod;
while (T--) {
int l = read(), r = read();
int ans = (((sum[r] - sum[l - ]) % mod) + mod) % mod;
printf("%d\n", ans);
}
}