NPY and girls
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1436 Accepted Submission(s): 491
Here comes the problem,(NPY doesn't want to learn how to use excavator),he wonders how many different ways there can be in which he can visit his girls.The different ways are different means he visits these classrooms in different order.
For each test case,there are two integers n,m(0<n,m≤30000) in the first line.N is the number of girls,and M is the number of times that NPY want to visit his girls.
The following single line contains N integers, a1,a2,a3,…,an , which indicates the class number of each girl. (0<ai≤30000)
The following m lines,each line contains two integers l,r(1≤l≤r≤n) ,which indicates the interval NPY wants to visit.
2 4 2 1 2 1 3 1 3 1 4 1 1 1 1 1
3 12 1
比如 : 三个女孩 1 1 2 询问 [1,3] 那么就有 1 1 2 , 1 2 1, 2 1 1 三种情况
思路:
我们继续根据上面的那个例子来找规律。 当有三个女生 1 1 2 的时候答案是3
那么加多一个 2 的女生的时候会是什么情况呢? _1_1_2_ 我们可以看到,新来的女生可以在这四个位置中挑一个坐
那么原来有 3 种,现在有 4种坐法,所以就有 3 * 4 = 12 种情况了,但是我们会发现 _1_1_22 和 _1_122_ 这两种是一样的,答案应该是 6种 其实就是四个空位来分给 两个 1 和两个 2 ans2 = C[4][2] * C[4 - 2][2]
那么原来 1 1 2 的时候是 ans1 = C[3][2] * C[3 - 2][1]
这两者之间的关系就是 ans2 = ans1 * 4 / 2 也就是 C[3][2] * C[3 - 2][1] * (3 + 1) / (1 + 1) = C[4][2]
他的实际含义就是 有 4 个空位可以插入,但是有 2 个 2,所以有 重复的 所以应该是 * 4 / 2
那么同理 1 1 1 2 的情况由 1 1 2 得来就是 = 3 * 4 / 3 = 4
所以 对于新增加一个值x 则 flag[x]++ Ans = Ans * (r - l + 1) / (flag[x])
对于减的就相反操作 Ans = Ans * flag[x] / (r - 1 + 1) flag[x]--
做除法的时候没法取模,所以要用逆元 inv[] 去做除法 所以 Ans / (flag[x]) = Ans * inv[flag[x]]
需要注意的是 不能写成 dele(a[l++]) 而要写成 dele(a[l]) , l++ ,否则在上传了值之后 l 就变了的话,区间长度也变了,答案就会计算错误
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define maxn 30030
#define mem(a,x) memset(a,x,sizeof(a))
#define ll long long
const ll mod = 1000000007;
struct quse{
int l,r,id,pos;
}q[maxn];
int n,m,a[maxn],flag[maxn];
int l,r;
ll Ans,ans[maxn];
ll inv[maxn];
int cmp(quse a,quse b){
if(a.pos != b.pos)
return a.pos < b.pos;
return a.r < b.r;
}
ll Pow(ll a,ll b){
ll tmp = 1;
while(b){
if(b & 1){
tmp *= a;
tmp %= mod;
}
a *= a;
a %= mod;
b /= 2;
}
return tmp;
}
void init(){
for(int i = 1;i <= 30000;i++)
inv[i] = Pow(i,mod - 2);
}
void add(int x){
flag[x]++;
Ans = Ans * (r - l + 1) % mod;
Ans = Ans * inv[flag[x]] % mod;
}
void dele(int x){
Ans = Ans * flag[x] % mod;
Ans = Ans * inv[r - l + 1] % mod;
flag[x]--;
}
int main(){
init();
int T;
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
int block = sqrt(n);
for(int i = 1;i <= n;i++)
scanf("%d",&a[i]);
for(int i = 1;i <= m;i++){
scanf("%d %d",&q[i].l,&q[i].r);
q[i].id = i;
q[i].pos = q[i].l / block;
}
sort(q + 1,q + 1 + m,cmp);
mem(ans,0);
mem(flag,0);
l = 1,r = 0;
Ans = 1;
for(int i = 1;i <= m;i++){
while(q[i].r > r){
add(a[++r]);
}
while(q[i].r < r){
dele(a[r]);
r--;
}
while(q[i].l > l){
dele(a[l]);
l++;
}
while(q[i].l < l){
add(a[--l]);
}
ans[q[i].id] = Ans;
}
for(int i = 1;i <= m;i++)
printf("%lld\n",ans[i]);
}
return 0;
}
/*
2
10 3
1 2 3 1 2 1 3 2 1 5
1 10
2 9
4 6
*/