Hdu5145NPY and girls莫队算法

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;
}
时间: 2024-10-29 01:10:19

Hdu5145NPY and girls莫队算法的相关文章

HDU 5145 NPY and girls 莫队算法

对于这类区间查询的问题,如果可以用O(1)的复杂度推到一个曼哈顿距离为1的另外区间的话,就可以直接用莫队算法搞. 从网上搜到的有两种搞法.第一种是先建立曼哈顿距离最小生成树,然后直接dfs遍历整棵树来求解的. 还有一种是先分块,然后把查询按照块的编号为第一关键字,右边界为第二关键字排序,排序直接直接暴力转移. 这样做的复杂度是n * sqrt(n),后面那个sqrt(n)取决于是怎么分块的. 仔细想想感觉这样子搞复杂度差不多就是这样,因为在同一个块中的复杂度怎么搞都是sqrt(n)级别的,就算是

HDU 5145 NPY and girls(莫队算法+乘法逆元)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5145 [题目大意] 给出一个数列,每次求一个区间数字的非重排列数量.答案对1e9+7取模. [题解] 我们发现每次往里加入一个新的数字或者减去一个新的数字,前后的排列数目是可以通过乘除转移的,所以自然想到用莫队算法处理.因为答案要求取模,所以在用除法的时候要计算逆元. [代码] #include <cstdio> #include <algorithm> #include <

莫队算法

Beautiful Girl 题意 给定一个长度为 n 的序列 a[1], a[2], ..., a[n] . m 组询问 (l, r, K) , 求区间 [l, r] 去除重复的数之后的第 K 小. n, m <= 100000 . 分析 莫队算法 + 值域分块. 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include &

BZOJ4241 历史研究 莫队算法 堆

欢迎访问~原文出处--博客园-zhouzhendong&AK 去博客园看该题解 题目 Description IOI国历史研究的第一人--JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. 日记中记录了连续N天发生的时间,大约每天发生一件. 事件有种类之分.第i天(1<=i<=N)发生的事件的种类用一个整数Xi表示,Xi越大,事件的规模就越大. JOI教授决定用如下的方法分析这些日记: 1.

CodeForces - 86D 莫队算法

http://codeforces.com/problemset/problem/86/D 莫队算法就是调整查询的顺序,然后暴力求解. 每回可以通过现有区间解ans(l,r)得到区间(l+1,r),(l-1,r),(l,r+1),(l,r-1)的区间解. 调整方式http://blog.csdn.net/bossup/article/details/39236275 这题比那个还要简单,查询的是K^2*Z,很清楚就是莫队算法,然而做的时候没有学过,回来补题补到 关键是我一直没明白为什么重载小于号

codeforces 617 E. XOR and Favorite Number(莫队算法)

题目链接:http://codeforces.com/problemset/problem/617/E 题目: 给你a1 a2 a3 ··· an 个数,m次询问:在[L, R] 里面又多少中 [l, r] 使得 al xor al+1 xor ··· ar 为 k. 题解: 本题只有区间查询没有区间修改,而且数据量不大(10w),所以可以用离线的方法解决. 使用莫队算法来解决,就需要O(1)的修改[L, R+1] .[L, R-1].[L+1, R].[L-1, R]. 详细的莫队可以百度学一

(普通的)莫队算法简单介绍

莫队算法(由莫涛发明的)是一种离线的暴力算法(至少我这么认为).使用莫队算法的条件是,知道一个区间[l, r]的结果,那么也可以快速知道[l + 1, r],[l - 1, r], [l, r - 1], [l, r + 1]这四个区间的结果.于是可以想到,直接通过这样转移来解决一些问题.当然有些出题人机智,故意卡这种暴力,让你从头跑到尾然后从尾跑到头,于是时间复杂度高达O(n2) 而莫队算法就是通过改变处理询问的顺序来降低时间复杂度. 比如说现在知道一个区间[l1, r1],又要转移到[l2,

莫队算法良心讲解

问题:有n个数组成一个序列,有m个形如询问L, R的询问,每次询问需要回答区间内至少出现2次的数有哪些. 朴素的解法需要读取O(nm)次数.如果使用STL的Map来保存出现的次数,每次需要O(nmlogn)的复杂度.有没有更快的方法呢? 注意到询问并没有强制在线,因此我们可以使用离线方法.注意到一点,如果我们有计算完[L, R]的map,那么[L - 1, R].[L + 1, R].[L, R - 1].[L, R + 1]都能够在O(logn)的复杂度得出.是否能安排适当的询问顺序,使得每次

清橙A1206 小Z的袜子(莫队算法)

A1206. 小Z的袜子 时间限制:1.0s   内存限制:512.0MB 总提交次数:744   AC次数:210   平均分:44.44 将本题分享到: 查看未格式化的试题   提交   试题讨论 试题来源 2010中国国家集训队命题答辩 问题描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是