题意:给出一个序列,然后m个询问,每次询问[l,r]中的方案数,方案数指的是所有询问
区间中数字的组合数.
因为C(m+1,n+1)=C(m,n)*(m+1)/(n+1),所以增加和删除就可以O(1)求出来辣.
#include
using namespace std;
#define maxn 31111
#define mod 1000000007
int pos[maxn];
int n, m, k;
long long cnt[maxn];
long long ans[maxn], tmp[maxn];
struct node {
int l, r, id;
bool operator < (const node &a) const {
return pos[l] < pos[a.l] || (pos[l] == pos[a.l] && r < a.r);
}
long long ans;
} p[maxn];
int a[maxn];
long long cur;
bool cmp (const node &a, const node &b) {
return a.id < b.id;
}
int l, r;
long long rev[maxn];
void add (int pos) {
int n = cnt[a[pos]], m = r-l;
cnt[a[pos]]++;
cur = cur * (m+1)%mod * rev[n+1]%mod;
}
void del (int pos) {
cnt[a[pos]]--;
int n = cnt[a[pos]], m = r-l;
cur = cur * (n+1)%mod * rev[m+1]%mod;
}
void init () {
rev[1] = 1;
for (int i = 2; i < maxn; i++){
rev[i] = (long long)(mod - mod/i) * rev[mod % i] % mod;
}
}
int main () {
//freopen ("in.txt", "r", stdin);
init ();
int t;
scanf ("%d", &t);
while (t--) {
scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf ("%d", &a[i]);
}
int block = ceil (sqrt (n*1.0));
for (int i = 1; i <= n; i++) pos[i] = (i-1)/block;
for (int i = 0; i < m; i++) {
scanf ("%d%d", &p[i].l, &p[i].r);
p[i].id = i;
}
sort (p, p+m);
l = 1, r = 1;
cur = 0;
memset (cnt, 0, sizeof cnt);
add (1);
cur = 1;
for (int i = 0; i < m; i++) {
while (r > p[i].r) {
del (r);
r--;
}
while (r < p[i].r) {
r++;
add (r);
}
while (l > p[i].l) {
l--;
add (l);
}
while (l < p[i].l) {
del (l);
l++;
}
ans[p[i].id] = cur;
}
for (int i = 0; i < m; i++) {
printf ("%lld\n", ans[i]);
}
}
return 0;
}