您的位置:首页 > 其它

HDU - 5145 莫队算法

2017-04-10 19:44 417 查看

题意:

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5145

有n个女生,每个女生都属于一个教室,现在要访问这些女生,就要进入教室,每次进入一个教室只能访问该教室的一个女生,现在要问对于[L,R]之间的女生全部访问,一共有多少种不同的访问教室的方式?

思路:

仔细想一下,因为最后的方案按照教室的不同来划分,那就与教室内部的女生访问顺序没有关系,那么只要拿所有女生的访问的排列数除以每个教室女生的排列数即可。

区间查询问题,不涉及修改操作,而且区间改变一个单位的大小只需要O(1)的时间,典型的莫队算法可以处理的类型。

分块加速,以及要求逆元。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MOD = 1e9 + 7;
const int MAXN = 3e4 + 10;

LL inv[MAXN];

void init() {
inv[0] = inv[1] = 1;
for (int i = 2; i <= 30000; i++)
inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
}

LL cur, num;
int cnt[MAXN], a[MAXN], p[MAXN];

void add(int pos) {
++num; ++cnt[a[pos]];
cur = cur * num % MOD;
cur = cur * inv[cnt[a[pos]]] % MOD;
}

void del(int pos) {
cur = cur * inv[num] % MOD;
cur = cur * cnt[a[pos]] % MOD;
cnt[a[pos]]--; num--;
}

struct Query {
int l, r, id;
bool operator < (const Query &rhs) const {
return p[l] == p[rhs.l] ? r < rhs.r : p[l] < p[rhs.l];
}
} q[MAXN];

LL ans[MAXN];

int main() {
//freopen("in.txt", "r", stdin);
init();
int T;
scanf("%d", &T);
while (T--) {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
int block = ceil(sqrt(n));
for (int i = 1; i <= n; i++) p[i] = (i - 1) / block;
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);
memset(cnt, 0, sizeof(cnt));
cur = 0, num = 0;
add(1);
cur = 1;
int l = 1, r = 1;
for (int i = 1; i <= m; i++) {
while (r > q[i].r) {
del(r);
r--;
}
while (r < q[i].r) {
++r;
add(r);
}
while (l > q[i].l) {
--l;
add(l);
}
while (l < q[i].l) {
del(l);
l++;
}
ans[q[i].id] = cur;
}
for (int i = 1; i <= m; i++)
printf("%I64d\n", ans[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm 莫队算法