先找出第二类斯特林数的公式,然后把公式分解成卷积的形式,先做一遍NTT,然后对于每次询问只要用线段树求出有多少个空闲的房间就可以了。
#include <bits/stdc++.h> using namespace std; typedef long long LL; #define lson o << 1, L, mid #define rson o << 1 | 1, mid+1, R #define ls o << 1 #define rs o << 1 | 1 const int maxn = 300005; const int mod = 880803841; LL powmod(LL a, LL b, LL p) { LL base = a, res = 1; while(b) { if(b % 2) res = res * base % p; base = base * base % p; b /= 2; } return res; } namespace NTT { const int r = 26, gl = 25; LL p, rp[50], irp[50]; void setMod(LL _p = 880803841) { p = _p; for(int i = 0; i < gl; i++) rp[i] = powmod(r, (p-1)/(1<<i), p); } void FFT(LL a[], int n, LL wt[] = rp) { for(int i = 0, j = 0; i < n; i++) { if(j > i) swap(a[i], a[j]); int k = n; while(j & (k >>= 1)) j &= ~k; j |= k; } for(int m = 1, b = 1; m < n; m<<=1, b++) for(int k = 0, w = 1; k < m; ++k) { for(int i = k; i < n; i += m<<1) { int v = a[i+m] * w % p; if((a[i+m] = a[i] - v) < 0) a[i+m] += p; if((a[i] += v) >= p) a[i] -= p; } w = w * wt[b] % p; } } void IFFT(LL a[], int n) { for(int i = 0; i < gl; i++) irp[i] = powmod(rp[i], n-1, p); FFT(a, n, irp); LL inv = powmod(n, p-2, p); for(int i = 0; i < n; i++) a[i] = a[i] * inv % p; } void Mul(LL a[], LL b[], LL n, LL c[]) { FFT(a, n);FFT(b, n); for(int i = 0; i < n; i++) c[i] = a[i] * b[i] % p; IFFT(c, n); } } LL a[maxn]; LL b[maxn]; LL c[maxn]; int sum[100005 << 2]; int lazy[100005 << 2]; void pushup(int o) { sum[o] = sum[ls] + sum[rs]; } void pushdown(int o, int L, int R) { if(lazy[o]) { int mid = (L + R) >> 1; sum[ls] = (mid - L + 1) - sum[ls]; sum[rs] = (R - mid) - sum[rs]; lazy[ls] ^= lazy[o]; lazy[rs] ^= lazy[o]; lazy[o] = 0; } } void build(int o, int L, int R) { lazy[o] = 0; if(L == R) { sum[o] = 1; return; } int mid = (L + R) >> 1; build(lson); build(rson); pushup(o); } void update(int o, int L, int R, int ql, int qr) { if(ql <= L && qr >= R) { sum[o] = (R - L + 1) - sum[o]; lazy[o] = lazy[o] ^ 1; return; } pushdown(o, L, R); int mid = (L + R) >> 1; if(ql <= mid) update(lson, ql, qr); if(qr > mid) update(rson, ql, qr); pushup(o); } void work() { int N, m, D; scanf("%d%d%d", &N, &m, &D); memset(a, 0, sizeof a); memset(b, 0, sizeof b); int n = 1; while(N >= n) n *= 2; a[0] = 1; for(int i = 1; i <= N; i++) a[i] = a[i-1] * i % mod; for(int i = 0; i <= N; i++) a[i] = b[i] = powmod(a[i], mod - 2, mod); for(int i = 1; i <= N; i+=2) a[i] = a[i] * (mod - 1) % mod; for(int i = 0; i <= N; i++) b[i] = b[i] * powmod(i, N, mod) % mod; n = n * 2; NTT::setMod(); NTT::Mul(a, b, n, c); build(1, 1, m); while(D--) { int ql, qr; scanf("%d%d", &ql, &qr); update(1, 1, m, ql, qr); int t = sum[1]; printf("%lld\n", c[t]); } } int main() { int _; scanf("%d", &_); while(_--) work(); return 0; }