zoukankan      html  css  js  c++  java
  • HDU 5145

    题意: cases T(1≤T≤10) (0<n,m≤30000) (0<ai≤30000)
          

        n个数ai 表示n个女孩所在教室

        m次询问 [L,R](1 <= L <= R <= n)
         

        问访问所有女孩的顺序方案数(进教室顺序)为多少(一次进教室只能访问一个人)
        
    分析:

        莫队算法 + 排列数

        一个区间内的方案数为 C(m,c1)*C(m-c1,c2)*C(m-c1-c2,c3)*....*C(cn,cn)
          

        每次转移通过下式:

         C(m+1,n+1) = C(m,n) * (m+1/n+1)
             

         C(m,n) = C(m+1,n+1) * (n+1/m+1) (对于缩小的过程而言)
        
          因为需要对大素数取模,除法就是乘上对应的乘法逆元,故先用费马小定理

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int MOD = 1000000007;
    const int MAXN = 30005;
    const int MAXM = 30005;
    struct Query
    {
        int L,R,id;
    }node[MAXM];
    struct Ans
    {
        long long a;
    }ans[MAXM];
    int a[MAXN],num[MAXN];
    long long inv[MAXN];//乘法逆元 
    int t,n,m,unit;
    void work()
    {
        long long temp = 1;
        memset(num,0,sizeof(num));
        int L = 1 , R = 0;
        for(int i = 0; i < m ; i++)
        {
            while(R < node[i].R)//C(m+1,n+1) = C(m,n)*(m+1/n+1)
            {
                R++;
                num[a[R]]++;
                temp = temp * (R - L + 1) % MOD * inv[num[a[R]]] % MOD;
            }
            while(R > node[i].R)//C(m,n) = C(m+1,n+1)*(n+1/m+1)
            {
                temp = temp * num[a[R]] % MOD * inv[R - L + 1] % MOD;
                num[a[R]]--;
                R--;
            }
            while(L < node[i].L)//C(m,n) = C(m+1,n+1)*(n+1/m+1)
            {
                temp = temp * num[a[L]] % MOD * inv[R - L + 1] % MOD;
                num[a[L]]--;
                L++;
            }
            while(L > node[i].L)//C(m+1,n+1) = C(m,n)*(m+1/n+1)
            {
                L--;
                num[a[L]]++;
                temp = temp * (R - L + 1) % MOD * inv[num[a[L]]] % MOD;
            }
            ans[node[i].id].a = temp;
        }
    }
    bool cmp(Query a,Query b)
    {
        if(a.L/unit != b.L/unit) return a.L/unit < b.L/unit;
        else return a.R < b.R;
    }
    void Init()//femat
    {
        inv[1] = 1;
        for(int i = 2; i < MAXN; i++) 
            inv[i] = inv[MOD % i] * (MOD - MOD / i) % MOD;
    }
    int main()
    {
        Init();
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            for(int i = 1; i <= n; i++) 
                scanf("%d",&a[i]);
            for(int i = 0; i < m; i++)
            {
                scanf("%d%d",&node[i].L,&node[i].R);
                node[i].id = i;
            }
            unit = (int)sqrt(n);
            sort(node,node+m,cmp);
            work();
            for(int i = 0; i < m ;i++)
                printf("%lld
    ",ans[i].a);
        }
    } 
    我自倾杯,君且随意
  • 相关阅读:
    专题——递归
    今日听郝斌老师鸡汤
    线性结构的两种常见应用之一 队列
    线性结构的两种应用之一——栈
    C++常用库函数
    洛谷 标志重捕法?
    c++复习——临考前的女娲补天 >=.<
    c++复习——类(2)
    c++复习——类(1)
    Python单元测试
  • 原文地址:https://www.cnblogs.com/nicetomeetu/p/5709207.html
Copyright © 2011-2022 走看看