HDU_1175_莫队+逆元

http://acm.hdu.edu.cn/showproblem.php?pid=5145

初探莫队,就是离线排序后的暴力,但是效率大大提高,中间要除法取模,所以用到了逆元。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define LL long long
#define MOD 1000000007
using namespace std;

int a[30005],num[30005],n,m,sizee;
LL ans[30005],inv[30005];
struct node
{
    int l,r,num,belong;
}query[30005];

void init()
{
    for(int i = 1;i <= 30000;i++)
    {
        LL temp = 1,x = i;
        int pow = MOD-2;
        while(pow)
        {
            if(pow%2)    temp = temp*x%MOD;
            x = x*x%MOD;
            pow /= 2;
        }
        inv[i] = temp;
    }
}

int cmp(node x,node y)
{
    if(x.belong == y.belong)    return x.r < y.r;
    return x.l<y.l;
}

int main()
{
    init();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        sizee = sqrt(n);
        for(int i = 1;i <= n;i++)    scanf("%d",&a[i]);
        for(int i = 1;i <= m;i++)
        {
            scanf("%d%d",&query[i].l,&query[i].r);
            query[i].num = i;
            query[i].belong = (query[i].l-1)/sizee+1;
        }
        sort(query+1,query+1+m,cmp);
        memset(num,0,sizeof(num));
        int ll = 1,rr = 1;
        LL now = 1;
        num[a[1]]++;
        for(int i = 1;i <= m;i++)
        {
            while(rr < query[i].r)
            {
                rr++;
                num[a[rr]]++;
                now = now*(rr-ll+1)%MOD*inv[num[a[rr]]]%MOD;
            }
            while(ll > query[i].l)
            {
                ll--;
                num[a[ll]]++;
                now = now*(rr-ll+1)%MOD*inv[num[a[ll]]]%MOD;
            }
            while(ll < query[i].l)
            {
                now = now*num[a[ll]]%MOD*inv[rr-ll+1]%MOD;
                num[a[ll]]--;
                ll++;
            }
            while(rr > query[i].r)
            {
                now = now*num[a[rr]]%MOD*inv[rr-ll+1]%MOD;
                num[a[rr]]--;
                rr--;
            }
            ans[query[i].num] = now;
        }
        for(int i = 1;i <= m;i++)    printf("%lld\n",ans[i]);
    }
    return 0;
}
时间: 2024-10-17 08:54:25

HDU_1175_莫队+逆元的相关文章

hdu NPY and girls 莫队+逆元

NPY and girls Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) 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 to

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

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

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

【HDU 5145】 NPY and girls(组合+莫队)

pid=5145">[HDU 5145] NPY and girls(组合+莫队) NPY and girls Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 593    Accepted Submission(s): 179 Problem Description NPY's girlfriend blew him out!H

HDU 5145 NPY and girls 莫队算法

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

HDU 6333 莫队+组合数

Problem B. Harvest of Apples Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 2397    Accepted Submission(s): 934 Problem Description There are n apples on a tree, numbered from 1 to n.Count th

HDU-6333 Problem B. Harvest of Apples 莫队

HDU-6333 题意:有n个不同的苹果,你最多可以拿m个,问有多少种取法,多组数据,组数和n,m都是1e5,所以打表也打不了. 思路:这道题要用到组合数的性质,记S(n,m)为从n中最多取m个的方法总数,显然是C(n,0),C(n,1)……C(n,m)的和. 显然S(n,m+1) = S(n, m) + C(n,m+1); 还有一个等式就不那么明显了,S(n+1,m) = 2 * S(n,m) - C(n,m); 我也是在王神犇的指导下明白的. 既然知道了一组(n,m)是可以在很快的时间下转移

HDU6333 莫队+组合数

题目大意: 给定n m 在n个数中最多选择m个的所有方案 #include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LL long long const int mod=1e9+7; const int N=1e5+5; /********组合数模板*********/ LL pow_mod(LL a, LL b) { LL res = 1LL; a %= mod; while(b){ if(b &

(莫队算法)CodeForces - 617E XOR and Favorite Number

题意: 长度为n的数列,m次询问,还有一个k.每次询问询问询问从数列的L到R内有多少个连续子序列异或起来等于k. 分析: 因为事先知道这题可以用莫队写,就正好用这题练习莫队. 预处理每个前缀异或和. 然后莫队按分块排序后,不断更新,用一个数组cnt[]记录当前L到R前缀和的数量. R向右拉,新增的数量就是cnt[pre^k],pre表示当前这个R位置的前缀异或和,然后更新一下cnt. 其他的也类似. 算是一个比较好的入门题. 代码: 1 #include <cstdio> 2 #include