HDU - 5145 莫队+乘法逆元

http://acm.hdu.edu.cn/showproblem.php?pid=5145 (题目连接)

给出一个数列,每次求一个区间数字的非重排列数量。答案对1e9+7取模。

每次往里加入一个新的数字或者减去一个新的数字,前后的排列数目是可以通过乘除转移。答案要求取模,在用除法的时候要用到逆元,需要离线处理。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn=30000;
const ll mod=1e9+7;
int t,n,m,a[maxn+50],T;
ll c[maxn+50],an[maxn+50];
struct node{
    int l,r,id;
}s[maxn+50];
bool cmp(const node &a,const node &b)
{
    if(a.l/t==b.l/t) return a.r>b.r;
    return a.l<b.l;
}
ll qmod(ll n,ll p)
{
    ll ans=1;
    while(p)
    {
        if(p&1) ans=ans*n%mod;
        p>>=1;
        n=n*n%mod;
    }
    return ans;
}
ll inv[maxn+50];
void init()
{
    for(int i=0;i<=maxn;i++)
    inv[i]=qmod(1ll*i,mod-2);
}
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=1;i<=m;i++)
        {
            scanf("%d%d",&s[i].l,&s[i].r);
            s[i].id=i;
        }
        t=(int)(sqrt(n)+0.5);
        sort(s+1,s+m+1,cmp);

        int l=1,r=0;
        memset(c,0,sizeof c);
        ll ans=1,sum=0;
        for(int i=1;i<=m;i++)
        {
            while(l<s[i].l)
            {
                if(sum>0)
                ans=ans*inv[sum]%mod;
                if(c[a[l]]>0)
                    ans=ans*c[a[l]]%mod;
                c[a[l]]--;
                sum--;
                l++;
            }
            while(l>s[i].l)
            {
                l--;
                c[a[l]]++;
                sum++;
                if(sum>0)
                ans=ans*sum%mod;
                if(c[a[l]]>0)
                    ans=ans*inv[c[a[l]]]%mod;
            }

            while(r>s[i].r)
            {
                if(sum>0)
                ans=ans*inv[sum]%mod;
                if(c[a[r]]>0)
                    ans=ans*c[a[r]]%mod;
                c[a[r]]--;
                sum--;
                r--;
            }
            while(r<s[i].r)
            {
                r++;
                c[a[r]]++;
                sum++;
                if(sum>0)
                ans=ans*sum%mod;
                if(c[a[r]]>0)
                    ans=ans*inv[c[a[r]]]%mod;
            }

            an[s[i].id]=ans;
        }

        for(int i=1;i<=m;i++)
            printf("%lld\n",an[i]);

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dllpxfire/article/details/80502632
今日推荐