HDU 5145 分块 莫队
给定n个数,q个询问[l,r]区间,每次询问该区间的全排列多少种。
数值都是30000规模
首先考虑计算全排列,由于有同种元素存在,相当于每次在len=r-l+1长度的空格随意放入某种元素即$\binom{len}{k_1}$,那么下种元素即为$\binom{len-k_1}{k2}$,以此类推,直至最后直接填满,那么全排列为${\frac{len!}{k_1!k_2!…k_n!}}$
然后可以发现可以直接O(1)求得左右相邻区间的值(就是乘或除),那么考虑分块莫队。
/** @Date : 2017-09-23 18:57:10 * @FileName: HDU 5145 分块 莫队.cpp * @Platform: Windows * @Author : Lweleth (SoungEarlf@gmail.com) * @Link : https://github.com/ * @Version : $Id$ */ #include <bits/stdc++.h> #define LL long long #define PII pair<int ,int> #define MP(x, y) make_pair((x),(y)) #define fi first #define se second #define PB(x) push_back((x)) #define MMG(x) memset((x), -1,sizeof(x)) #define MMF(x) memset((x),0,sizeof(x)) #define MMI(x) memset((x), INF, sizeof(x)) using namespace std; const int INF = 0x3f3f3f3f; const int N = 1e5+20; const double eps = 1e-8; const LL mod = 1e9 + 7; int k[30010]; int a[30010]; int blc[30010]; LL fac[30010]; LL inv[30010]; LL res[30010]; struct yuu { LL l, r; int m; }b[30010]; int cmp(yuu a, yuu b) { if(blc[a.l] != blc[b.l]) return a.l < b.l; return a.r < b.r; } void init() { fac[0] = fac[1] = 1; inv[0] = inv[1] = 1; for(LL i = 2; i <= 30005; i++) { fac[i] = (fac[i - 1] * i % mod + mod) % mod; inv[i] = (mod - mod / i) * inv[mod % i] % mod; } } int main() { init(); int T; cin >> T; while(T--) { LL n, q; scanf("%lld%lld", &n, &q); int sqr = sqrt(1.0 * n); for(int i = 1; i <= n; i++) scanf("%d", a + i), blc[i] = (i - 1) / sqr + 1; for(int i = 1; i <= q; i++) { scanf("%lld%lld", &b[i].l, &b[i].r); b[i].m = i; } sort(b + 1, b + 1 + q, cmp); MMF(k); LL l = 1, r = 0; LL ans = 1, cnt = 0; for(int i = 1; i <= q; i++) { while(r < b[i].r) { r++; k[a[r]]++; cnt++; ans = (ans * cnt % mod * inv[k[a[r]]] % mod + mod) % mod; } while(l > b[i].l) { l--; cnt++; k[a[l]]++; ans = (ans * cnt % mod * inv[k[a[l]]] % mod + mod) % mod; } while(r > b[i].r) { ans = (ans * inv[cnt] % mod * k[a[r]] % mod + mod) % mod; cnt--; k[a[r]]--; r--; } while(l < b[i].l) { ans = (ans * inv[cnt] % mod * k[a[l]] % mod + mod) % mod; cnt--; k[a[l]]--; l++; } while(ans < 0) ans += mod; res[b[i].m] = ans; } for(int i = 1; i <= q; i++) printf("%lld\n", res[i]); } return 0; }