参考https://www.cnblogs.com/liyinggang/p/5670623.html
题意:总共m个女生,分布在n个教室中,每个教室Hash[i]人,一个人要拜访每个女生,一个教师只能拜访一个女生,问摆放顺序的种类有多少种。
题解:总和ans=m!/(Hash[1]!*Hash[2]!*...*Hashn]!);
套莫队的模板,当询问区间从[l,r-1]->[l,r]时,设之前的区间[l,r-1]里面的排列数为ans,则[l,r]的结果应当为 ans*(r-l+1)/Hash[a[r]] 。反之,当现在的区间从[l,r+1]->[l,r]时,则当前[l,r]里面的排列数应该变成了 ans*Hash[a[r+1]] /(r-l+1)个人.还有左边区间两种情况可以仿造这两种情况得出来。
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define N 2300010
#define ll long long
const int maxn=30005;
const ll mod=1000000007;
struct node
{
int l,r,id;
ll ans;
}aa[maxn];
int k;
bool cmp(node a,node b)
{
if(a.l/k==b.l/k) return a.r<b.r;
return a.l<b.l;
}
bool cmp_id(node a,node b)
{
return a.id<b.id;
}
ll pow_mod(ll a,ll n){
ll ans = 1;
while(n){
if(n&1) ans = ans*a%mod;
a = a*a%mod;
n>>=1;
}
return ans;
}
ll getinv(int x)
{
return pow_mod(x,mod-2);
}
ll a[maxn],inv[maxn],Hash[maxn];
int main(){
for(int i=1;i<=maxn;i++)
inv[i]=getinv(i);
int T;
int u,v,n,m,q;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
k=(int)sqrt(m+0.5);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&aa[i].l,&aa[i].r);
aa[i].id=i;
}
sort(aa+1,aa+1+m,cmp);
memset(Hash,0,sizeof(Hash));
Hash[a[1]]++;
ll ans=1;
for(int i=1,l=1,r=1;i<=m;i++)
{
while(r<aa[i].r){
r++;
Hash[a[r]]++;
ans = ans*(r-l+1)%mod*inv[Hash[a[r]]]%mod;
}
while(l>aa[i].l){
l--;
Hash[a[l]]++;
ans = ans*(r-l+1)%mod*inv[Hash[a[l]]]%mod;
}
while(r>aa[i].r){
ans = ans*Hash[a[r]]%mod*inv[r-l+1]%mod;
Hash[a[r]]--;
r--;
}
while(l<aa[i].l){
ans = ans*Hash[a[l]]%mod*inv[r-l+1]%mod;
Hash[a[l]]--;
l++;
}
aa[i].ans=ans;
}
sort(aa+1,aa+1+m,cmp_id);
for(int i=1;i<=m;i++)
printf("%lld\n",aa[i].ans);
}
return 0;
}