一.题目链接:
HDU-5145
二.题目大意:
NPY 要在 n 个女朋友里面选取一个去约会,有些女朋友可能会同班.
女朋友编号为 1 ~ n.
为了不引起矛盾,NPY 在一个班里只会选取一名女朋友去约会.
问在第 i ~ j 个女朋友之间选择,有多少种选法(考虑顺序不同,最终答案 % 1000000007).
三.分析:
先来看选法如何计算
假设在第 i ~ j 中选取,则共有 j - i + 1 个人,在不考虑同班的情况下共有 ( j - i + 1 ) ! 种取法.
假设第 i 班的女朋友数为 cnt[i]
则选取数为
对于题目描述来说
这是一个典型的离线算法区间处理问题,很明显用莫队算法.
接着考虑的就是莫队算法 while 循环里的操作.
由选取数公式得:加入一个元素,就乘以 ( j - i + 1 ) 并除以 cnt[i].
可惜不能直接除,删除一个元素同理.
那就计算 cnt[i] 的乘法逆元 用费马小定理( Mod 为质数 )就可以做.
初始化打表即可.
四.代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-4
#define PI acos(-1.0)
#define ll long long int
using namespace std;
const int M = (int)3e4 + 10;
ll Mod = 1000000007;
int a[M];
int cnt[M];
int block;
ll rev[M];
ll res[M];
struct node
{
int l;
int r;
int id;
} s[M];
ll quick_power(ll a, ll b)
{
ll sum = 1;
while(b)
{
if(b & 1)
sum = sum * a % Mod;
a = a * a % Mod;
b >>= 1;
}
return sum % Mod;
}
void modui(int n, int m)
{
int l, r;
l = 1;
r = 0;
ll sum = 1;
for(int i = 0; i < m; ++i)
{
while(r < s[i].r)
{
r++;
cnt[a[r]]++;
sum = sum * (r - l + 1) % Mod * rev[cnt[a[r]]] % Mod;
}
while(r > s[i].r)
{
sum = sum * cnt[a[r]] % Mod * rev[r - l + 1] % Mod;
cnt[a[r]]--;
r--;
}
while(l < s[i].l)
{
sum = sum * cnt[a[l]] % Mod * rev[r - l + 1] % Mod;
cnt[a[l]]--;
l++;
}
while(l > s[i].l)
{
l--;
cnt[a[l]]++;
sum = sum * (r - l + 1) % Mod * rev[cnt[a[l]]] % Mod;
}
res[s[i].id] = sum;
}
}
int cmp(node a, node b)
{
if(a.l / block != b.l / block)
return a.l / block < b.l / block;
return a.r < b.r;
}
void init()
{
for(int i = 0; i < M; ++i)
rev[i] = quick_power(i, Mod - 2);
}
int main()
{
init();
int T;
scanf("%d", &T);
while(T--)
{
memset(cnt, 0, sizeof(cnt));
memset(res, 0, sizeof(res));
int n, m;
scanf("%d %d", &n, &m);
block = (int)sqrt(n + 0.5);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
for(int i = 0; i < m; ++i)
{
int l, r;
scanf("%d %d", &l, &r);
s[i].l = l;
s[i].r = r;
s[i].id = i;
}
sort(s, s + m, cmp);
modui(n, m);
for(int i = 0; i < m; ++i)
printf("%lld\n", res[i]);
}
return 0;
}