HDU 5145 NPY and girls (莫队算法)
2014-12-14 12:07
274 查看
题目: LINK
题目给定一个长度为n的序列,给出m个查询,[L,R],求区间内重排的个数。计算很简单 (R - L -1)! / (II 每个相同数字个数的阶乘)
即使裸着排序,递推会TLE。
可以使用莫队算法,分块的写法比较简单。
这样写就是分块,每一块的大小为sqrt(n),L按照块号排序,之后按照R排序。之后的写法和之前写的一样。
我自己估算的这样搞的复杂度约为 O(m*sqrt(n) + n*sqrt(n));
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define INF 1000000000
typedef __int64 LL;
#define N 31111
LL t, n, m, num
, G;
const LL mod = 1000000007;
struct node {
LL l, r, id;
}p
;
LL ans
, f
, ff
, cou
;
int cmp(node x, node y) {
if(x.l / G != y.l / G) return x.l / G < y.l / G;
return x.r < y.r ;
}
LL pow_(LL x, LL y, LL mm) {
LL ret = 1;
while(y) {
if(y&1) {
ret *= x; ret %= mm;
}
y >>= 1;
x *= x; x %= mm;
}
return ret;
}
void init() {
f[0] = ff[0] = 1;
for(LL i = 1; i < N; i++) {
f[i] = f[i-1] * i; f[i] %= mod;
ff[i] = pow_(f[i], mod - 2, mod); // get Inv();
}
}
void work() {
LL tmp = 1;
memset(cou, 0, sizeof(cou));
int L = 1, R = 0;
for(int i = 1; i <= m; i++) {
while(R < p[i].r) {
R ++;
tmp = tmp * f[cou[num[R]]] % mod;
cou[num[R]] ++;
tmp = tmp * ff[cou[num[R]]] % mod;
}
while(R > p[i].r) {
tmp = tmp * f[cou[num[R]]] % mod;
cou[num[R]] --;
tmp = tmp *ff[cou[num[R]]] % mod;
R --;
}
while(L < p[i].l) {
tmp = tmp * f[cou[num[L]]] % mod;
cou[num[L]] --;
tmp = tmp * ff[cou[num[L]]] % mod;
L ++;
}
while(L > p[i].l) {
L --;
tmp = tmp * f[cou[num[L]]] % mod;
cou[num[L]] ++;
tmp = tmp * ff[cou[num[L]]] % mod;
}
ans[p[i].id] = f[R - L + 1] * tmp % mod;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
init();
scanf("%I64d", &t);
while(t--) {
scanf("%I64d%I64d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%I64d", &num[i]);
}
for(int i = 1; i <= m; i++) {
scanf("%I64d%I64d", &p[i].l, &p[i].r);
p[i].id = i;
}
G = (int) sqrt(1.0 * n);
sort(p+1, p+1+m, cmp);
work();
for(int i = 1; i <= m; i++) {
printf("%I64d\n", ans[i]);
}
}
return 0;
}
题目给定一个长度为n的序列,给出m个查询,[L,R],求区间内重排的个数。计算很简单 (R - L -1)! / (II 每个相同数字个数的阶乘)
即使裸着排序,递推会TLE。
可以使用莫队算法,分块的写法比较简单。
这样写就是分块,每一块的大小为sqrt(n),L按照块号排序,之后按照R排序。之后的写法和之前写的一样。
我自己估算的这样搞的复杂度约为 O(m*sqrt(n) + n*sqrt(n));
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define INF 1000000000
typedef __int64 LL;
#define N 31111
LL t, n, m, num
, G;
const LL mod = 1000000007;
struct node {
LL l, r, id;
}p
;
LL ans
, f
, ff
, cou
;
int cmp(node x, node y) {
if(x.l / G != y.l / G) return x.l / G < y.l / G;
return x.r < y.r ;
}
LL pow_(LL x, LL y, LL mm) {
LL ret = 1;
while(y) {
if(y&1) {
ret *= x; ret %= mm;
}
y >>= 1;
x *= x; x %= mm;
}
return ret;
}
void init() {
f[0] = ff[0] = 1;
for(LL i = 1; i < N; i++) {
f[i] = f[i-1] * i; f[i] %= mod;
ff[i] = pow_(f[i], mod - 2, mod); // get Inv();
}
}
void work() {
LL tmp = 1;
memset(cou, 0, sizeof(cou));
int L = 1, R = 0;
for(int i = 1; i <= m; i++) {
while(R < p[i].r) {
R ++;
tmp = tmp * f[cou[num[R]]] % mod;
cou[num[R]] ++;
tmp = tmp * ff[cou[num[R]]] % mod;
}
while(R > p[i].r) {
tmp = tmp * f[cou[num[R]]] % mod;
cou[num[R]] --;
tmp = tmp *ff[cou[num[R]]] % mod;
R --;
}
while(L < p[i].l) {
tmp = tmp * f[cou[num[L]]] % mod;
cou[num[L]] --;
tmp = tmp * ff[cou[num[L]]] % mod;
L ++;
}
while(L > p[i].l) {
L --;
tmp = tmp * f[cou[num[L]]] % mod;
cou[num[L]] ++;
tmp = tmp * ff[cou[num[L]]] % mod;
}
ans[p[i].id] = f[R - L + 1] * tmp % mod;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
init();
scanf("%I64d", &t);
while(t--) {
scanf("%I64d%I64d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%I64d", &num[i]);
}
for(int i = 1; i <= m; i++) {
scanf("%I64d%I64d", &p[i].l, &p[i].r);
p[i].id = i;
}
G = (int) sqrt(1.0 * n);
sort(p+1, p+1+m, cmp);
work();
for(int i = 1; i <= m; i++) {
printf("%I64d\n", ans[i]);
}
}
return 0;
}
相关文章推荐
- hdu 5145 莫队算法模板题
- HDU 5145 (莫队算法)
- HDU 5145 NPY and girls 莫队算法
- hdu_5145_NPY and girls(莫队算法+组合)
- HDU - 5145 NPY and girls(莫队算法+乘法逆元)
- HDU 5145 NPY and girls(莫队算法+乘法逆元)
- hdu 5145 NPY and girls && 莫队算法 && 逆元处理
- hdu 5145 NPY and girls(排列组合+莫队算法)
- hdu 5145(莫队算法+逆元)
- hdu 5145 NPY and girls (莫队算法)
- hdu_5145_NPY and girls(莫队算法+组合)
- hdu 1686看毛片算法
- HDU 2121 Ice_cream’s world II 无固定点的最小树形图 朱刘算法
- 【最大二分匹配匈牙利算法】hdu 3729
- hdu1150匈牙利算法最小点覆盖
- HDU 2063过山车 二分图最大匹配 匈牙利算法
- hdu 2063 最大二分匹配,匈牙利算法
- 匈牙利算法之hdu:2063
- hdu 2063 赤裸裸的匈牙利算法
- 【无定根朱刘算法】hdu 3072