题意:拜访n个女生,每个女生属于一个班级,每次只能访问一个班的一个女生,问访问所有女生有多少种顺序(顺序指的是班级顺序)
假设有n个女生,分别属于m个班级,每个班级有num(i)个女生,那么访问的种数就是n!/(num1!*num2!*...numm!),
假设区间缩小,第m个班女生少了一个的话结果就是原来的结果乘上numm / n 这里涉及到除法需要用到逆元 (a/b) % p == a*b^-1%p, b^-1次方是b相对于p的逆元,利用费马定理求得b相对于p的逆元是b^p-2,快速幂跑一下就好了
这题有个坑点有点不解:
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--;
如果我while的顺序按上面这么写的话就会WA,必须把两个R循环放在L循环上, 原本是想add函数里有用到(R-L+1)如果L循环放在上面的话R-L+1可能会出现负数,但是我把L循环放上面然后在(R-L+1)这里加上绝对值还是WA, 有点蒙
随机数大法好。。。写了个程序造数据跑了一下知道原因了,如果我把L循环放到R循环之上,那么先是L->Q[i].l然后再R->Q[i].r因为Q[i].r >= Q[i].l那么在R->Q[i].r的过程中一定会出现R+1==L的时候,也就是R-L+1 == 0,这时候加了绝对值也还是0,一乘,结果就变成零了
再更新一下说明为什么这样写样例能过,样例的查询左端点都是1,而初始的L也是1那么要使R-L+1==0也就是使R-1+1==0,只有当R==0时才成立,而我while (R < Q[i].r) ++R,add(R)这里++R是写在add前面的,那么就不存在R==0使得R-L+1==0,结果也就不会等于0了,你说巧不巧。。。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 3e4+5;
const int mod = 1000000007;
ll a[maxn],pos[maxn],cnt[maxn],n,m;
int L = 1, R = 0;
ll Ans, ans[maxn];
ll ni[maxn];
struct node
{
int l,r,id;
}Q[maxn];
int cmp(node a, node b)
{
if (pos[a.l] == pos[b.l])
return a.r < b.r;
return pos[a.l] < pos[b.l];
}
ll calc(ll a,ll b)
{
ll ans = 1;
while (b > 0)
{
if (b & 1)
ans = ans * a % mod;
a = a * a % mod;
b /= 2;
}
return ans;
}
void add(int x)
{
cnt[a[x]]++;
Ans = Ans * (R-L+1) % mod;
Ans = Ans * ni[cnt[a[x]]] % mod;
}
void del(int x)
{
Ans = Ans * cnt[a[x]] % mod;
Ans = Ans * ni[R-L+1] % mod;
cnt[a[x]]--;
}
int main()
{
for (int i = 1; i <= 30000; i++)
ni[i] = calc(i,mod-2);
ni[0] = 1;
int T;
scanf("%d",&T);
while (T--)
{
memset(cnt,0,sizeof(cnt));
scanf("%d%d",&n,&m);
int sz = sqrt(n);
for (int i = 1; i <= n; i++)
{
scanf("%lld",&a[i]);
pos[i] = i / sz;
}
for (int i = 1; i <= m; i++)
{
scanf("%d%d",&Q[i].l,&Q[i].r);
Q[i].id = i;
}
sort(Q+1,Q+1+m,cmp);
L = 1, R = 0, Ans = 1;
for (int i = 1; i <= m; i++)
{
int l = Q[i].l;
int r = Q[i].r;
while (R < Q[i].r) ++R,add(R);
while (R > Q[i].r) del(R),R--;
while (L < Q[i].l) del(L),L++;
while (L > Q[i].l) --L,add(L);
ans[Q[i].id] = Ans;
}
for (int i = 1; i <= m; i++)
printf("%lld\n",ans[i]);
}
return 0;
}