题意:拜访n个女生,每个女生属于一个班级,每次只能访问一个班的一个女生,问访问所有女生有多少种顺序(顺序指的是班级顺序)
假设有n个女生,分别属于m个班级,每个班级有num(i)个女生,那么访问的种数就是n!/(num1!*num2!*...numm!),
运用了乘法逆元解决除法的情况
但是有一个巨大的坑点:
while (L < Q[i].l) del(L),L++;
while (L > Q[i].l) --L,add(L);
while (R < Q[i].r) ++R,add(R);
while (R > Q[i].r) del(R),R--;
这样写就会wa
把R放在上面才能ac
转移的时候先更新右端点 再更新左端点 不然可能出现右端点在左端点左边的情况(可能导致wa)

#include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define ll long long #define pb push_back #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// const int N=30000+10; const ll mod=1000000007; ll a[N],cnt[N],ans[N],fac[N],inv[N],n,L,R,num=1,block,m,l,r; ll fast(ll x, ll n) { ll ans=1; while(n) { if(n&1)ans=(ans*x)%mod; x=(x*x)%mod; n>>=1; } return ans%mod; } void init() { fac[1]=fac[0]=1; inv[0]=inv[1]=1; rep(i,2,30000+5) { fac[i]=fac[i-1]*i%mod; inv[i]=(mod-mod/i)*inv[mod%i]%mod; } } void add(int x) { cnt[a[x]]++; num=num*cnt[a[x]]%mod; } void del(int x) { num=num*inv[cnt[a[x]]]%mod; cnt[a[x]]--; } struct node { ll l,r,block;int id; }s[N]; bool cmp(node a,node b) { return a.l/block==b.l/block?a.r<b.r:a.l<b.l; } int main() { init(); int cas;RI(cas); while(cas--) { CLR(cnt,0); cin>>n>>m; block=sqrt(n); rep(i,1,n)scanf("%lld",&a[i]); rep(i,1,m)scanf("%lld%lld",&s[i].l,&s[i].r),s[i].id=i,s[i].block=(s[i].l-1)/block+1; sort(s+1,s+1+m,cmp); L=1,R=1,num=1; cnt[a[1]]=1; rep(i,1,m) { l=s[i].l,r=s[i].r; while(R<r)add(++R); while(R>r)del(R--); while(L<l)del(L++); while(L>l)add(--L); ans[s[i].id]=fac[r-l+1]*fast(num,mod-2)%mod; } rep(i,1,m)printf("%lld ",ans[i]%mod); } return 0; }