【校隊排位賽#7 H】 HDU NPY and girls 莫隊算法 + 費馬最小定理 + 快速冪

NPY and girls
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2776 Accepted Submission(s): 896

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

題意:求對每個詢問裏面區間內元素的排列數(去重)

可以說是很明顯的莫隊模型了。
要知道簡單的排列組合原理
在這裏插入圖片描述
Add 和 Del函數裏面主要執行的就是
遇到一個x位置,對這個位置計數++,然後在上面的式子中添加當前的貢獻,比如len++了就乘上當前len,然後除以當前a[x]出現的個數。
唯一麻煩的就是除數求餘要用到費馬最小定理還有快速冪,解決這個問題就很簡單了。

#include <iostream>
#include <vector>
#include <cstdio>
#include <map>
#include <climits>
#include <string>
#include <cmath>
#include <cstring>
#include <stack>
#include <queue>
#include <algorithm>
#define maxn 30000+5
using namespace std;
typedef long long ll;
int static mod =  1000000007;
int  pos[maxn];
int a[maxn];
ll  Ans[maxn];
ll cnt[maxn];
ll Inv[maxn];
ll ans = 1;
ll len = 0;
int n;
int m;
struct  Q{
        int l;
        int r;
        int k;
}q[maxn];

inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}

void printi(ll x) {
    if(x / 10) printi(x / 10);
    putchar(x % 10 + '0');
}

void init()
{
        for(int i=0;i<=m;i++)
        Ans[i] = 0;
        for(int i=0;i<=n;i++)
        cnt[i] = 0;
}

bool cmp(Q a , Q b)
{
       if(pos[a.l]==pos[b.l])
       {
            if(pos[a.l]&1)
            return a.r<b.r;
            else
            return a.r>b.r;
       }
       return a.l<b.l;
}

void Add(int x)
{
        len++;
        cnt[a[x]]++;
        ans = (ans*len)%mod;
        ans = ans *Inv[cnt[a[x]]]%mod;
}

void Del(int x)
{     
       
        ans = (ans*Inv[len]) %mod;
        ans = ans * (cnt[a[x]]+mod)%mod;
         len--; cnt[a[x]] --;
}

ll quick_pow(ll x, ll p)
{
    if(!p)  return 1;
    ll ans = quick_pow(x,p>>1);
    ans =   ans*ans%mod;
    if(p&1)  ans = ans * x%mod;
    return ans;
}

ll inv(ll x)
{
        ll mo = mod;
        return quick_pow(x,mo-2);
}

int main()
{
    int kase;
    cin>>kase;
    for(ll i=1;i<=maxn;i++)  Inv[i] = inv(i);
    while(kase--)
    {
         n = read();
         m = read();
        init();
        int block = sqrt(n);
        for(int i=1;i<=n;++i)
        {
                a[i] = read();
                pos[i] = (i-1)/block + 1;
        }

        for(int i=1;i<=m;++i)
        {
                q[i].l = read();
                q[i].r = read();
                q[i].k = i;
        }


        sort(q+1,q+1+m,cmp);
        int L = 1, R = 0;
        ans = 1;
        len = 0;
        for(int i=1;i<=m;++i)
        {
                while(L>q[i].l)  Add(--L);
                while(R<q[i].r) Add(++R);
                while(L<q[i].l)  Del(L++);
                while(R>q[i].r) Del(R--);
                Ans[q[i].k] = ans;
        }
        for(int i=1;i<=m;++i)
        {
                printf("%lld\n",Ans[i]%mod);
        }
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章