莫队算法可以离线解决区间查询的问题,dp[i][j]可以O(1)得到dp[i+1][j]或dp[i][j+1],将l分为sqrt(l)块,按照块排序,再按照r排序,理论复杂度nsqrt(n);
#include<iostream>
#include<cstring>
#include<cstdio>
#include<ostream>
#include<istream>
#include<algorithm>
#include<queue>
#include<string>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#include<vector>
#define fi first
#define se second
#define ll long long
#define pii pair<int,int>
#define inf (1<<30)
#define PI acos(-1.0)
#define eps 1e-8
#define pb push_back
using namespace std;
const int maxn=110005;
const ll mod=1000000007;
int c[maxn];
int num[maxn];
int n,m;
int block;
struct Node
{
int l,r;
int id;
ll ans;
}node[maxn];
ll inv[maxn];
bool cmp(const Node& u,const Node& v)
{
if(u.l/block!=v.l/block)
return u.l/block<v.l/block;
return u.r<v.r;
}
bool cmp2(const Node& u,const Node& v)
{
return u.id<v.id;
}
ll powMod(ll a,ll b)
{
if(b==0) return 1;
ll ans=powMod(a,b/2);
ans=ans*ans%mod;
if(b&1)
ans=ans*a%mod;
return ans;
}
int main()
{
for(int i=0;i<=30000;i++) inv[i]=powMod(i,mod-2);
int t;
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
block=(int)sqrt(30000.0);
for(int i=1;i<=m;i++) {
scanf("%d%d",&node[i].l,&node[i].r);
node[i].id=i;
}
sort(node+1,node+m+1,cmp);
memset(num,0,sizeof(num));
int tot=0;
ll ans=1;
int L=1,R=0;
for(int i=1;i<=m;i++) {
while(R<node[i].r) {
R++;tot++;
num[c[R]]++;
ans=ans*tot%mod*inv[num[c[R]]]%mod;
}
while(R>node[i].r) {
ans=ans*inv[tot]%mod*num[c[R]]%mod;
num[c[R]]--;
R--; tot--;
}
while(L<node[i].l) {
ans=ans*inv[tot]%mod*num[c[L]]%mod;
num[c[L]]--;
L++; tot--;
}
while(L>node[i].l) {
L--; tot++;
num[c[L]]++;
ans=ans*tot%mod*inv[num[c[L]]]%mod;
}
node[i].ans=ans;
}
sort(node+1,node+m+1,cmp2);
for(int i=1;i<=m;i++)
printf("%I64d\n",node[i].ans);
}
return 0;
}