Problem Description
NPY‘s girlfriend blew him out!His honey doesn‘t love him any more!However, he has so many girlfriend candidates.Because there are too many girls and for the convenience of management, NPY numbered the girls from 1 to n.These girls are in different classes(some girls may be in the same class).And the i-th girl is in class ai.NPY wants to visit his girls frequently.Each time he visits some girls numbered consecutively from L to R in some order. He can only visit one girl every time he goes into a classroom,otherwise the girls may fight with each other(-_-!).And he can visit the class in any order.
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.
Input
The first line contains the number of test cases T(1≤T≤10).
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.
Output
For each visit,print how many ways can NPY visit his girls.Because the ans may be too large,print the ans mod 1000000007.
Sample Input
2
4 2
1 2 1 3
1 3
1 4
1 1
1
1 1
Sample Output
3
12
1
题意:给出一个长度为n的序列,然后m个查询 ,区间[li,ri]中排列的种类数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5145
就是求这个区间数目的全排列比上区间中相同数的个数的全排列的积。
由于数目比较多,可以用乘法逆元搞下。
乘法逆元:a×b ≡1 (mod m) 称b是a关于m的乘法逆元
1.就是求 a×b - k×m = 1 。可知 ax + by = t 一定有解 ,当 t = gcd(a,b) ×k ,k为整数时。所以仅当a和m互质时原方程有解。这个可以用exgcd 求, 任意一组满足条件的解都可以。
2.由费马小定理 X^(m-1) ≡ 1 (mod m),X×X^(m-2) ≡ 1(mod m) 所以 X^(m-2) mop m 就是X的乘法逆元。
剩下区间查询的就用莫队算法搞
将一个区间分成sqrt(n)块,然后按 sqrt(l),r 排序。时间约为sqrt(n)*(n) 。
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<cstdlib> #include<queue> #include<algorithm> using namespace std; typedef long long LL; const LL mod = 1e9+7; const LL maxn = 33333; LL n,m; LL ans[maxn]; LL color[maxn]; LL cnt[maxn]; LL d[maxn]; LL nd[maxn]; struct Node { LL l;LL r;LL id; }node[maxn]; LL unit; LL quick(LL a,LL b) { LL sum = 1; while(b){ if(b&1) sum*= a; sum%=mod; a*=a;a%=mod; b>>=1; } return sum; } void init() { d[0] = nd[0] = 1; for(LL i = 1;i<=maxn;i++) d[i] = i*d[i-1] %mod; for(LL i = 1;i<=maxn;i++) nd[i] = quick(d[i],mod-2); } int cmp(const Node &a,const Node &b) { if(a.l/unit == b.l/unit) return a.r < b.r; return a.l/unit<b.l/unit; } void gao() { LL temp = 1; LL l = 1;LL r = 0;// 由于初始区间 l >r ,所以下面循环得从r 开始,如果查询区间不是从1开始就会出现l经过一段,r重复经过这一段。 memset(cnt ,0 ,sizeof(cnt)); for(LL i = 0 ;i<m;i++){ while(r>node[i].r){ temp *= nd[cnt[color[r]]] ;temp %=mod; cnt[color[r]]--; temp *= d[cnt[color[r]]];temp %=mod; r--; } while(r<node[i].r){ r++; temp *=nd[cnt[color[r]]];temp %=mod; cnt[color[r]]++; temp *= d[cnt[color[r]]];temp %=mod; } while(l<node[i].l){ temp *= nd[cnt[color[l]]]; temp %=mod; cnt[color[l]]--; temp *= d[cnt[color[l]]]; temp %=mod; l++; } while(l>node[i].l){ l--; temp *= nd[cnt[color[l]]]; temp %=mod; cnt[color[l]]++; temp *= d[cnt[color[l]]];temp %=mod; } ans[node[i].id] = d[r-l+1] * quick(temp,mod-2) %mod; } } int main() { LL T; init(); cin>>T; while(T--){ cin>>n>>m; for(LL i = 1;i<=n;i++) scanf("%I64d",&color[i]); for(LL i = 0 ;i<m;i++){ scanf("%I64d%I64d",&node[i].l,&node[i].r); node[i].id = i; } unit = (LL) sqrt(n); sort(node,node+m,cmp); gao(); for(LL i = 0;i<m;i++){ printf("%I64d\n",ans[i]); } } return 0; }