HDU5145:5145 ( NPY and girls ) (莫队算法+排列组合+逆元)

传送门

题意

给出n个数,m次访问,每次询问[L,R]的数有多少种排列

分析

\(n,m<=30000\),我们采用莫队算法,关键在于区间如何\(O(1)\)转移,由排列组合知识得到,如果加入一个数,\(区间值*区间长度/该数出现次数\),减去一个数则相反操作讲解

trick

1.我的原先莫队写法不能ac,原因是我传入的L,R是全局变量,在insert和erase前就++,--了,而没有达到预期目的,把R++,L--分离即可

代码

//wa
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define F(i,a,b) for(int i=a;i<=b;++i)
#define R(i,a,b) for(int i=a;i<b;++i)
#define mem(a,b) memset(a,b,sizeof(a))
const ll mod = 1e9+7;
int t,n,m,len,L,R;
int a[30030],cnt[30030];
ll ans[30030],ret;
struct node
{
    int l,r,id,block;
    node(){}
    node(int l,int r,int id):l(l),r(r),id(id){block=l/len;}
    bool operator<(const node &p)const
    {
        return block==p.block?r<p.r:block<p.block;
    }
}e[30030];
ll inv[30030];
void get_inverse(int n, ll p) {
    inv[1] = 1;
    for (int i = 2; i <= n; ++i) {
        inv[i] = (p - p / i) * inv[p % i] % p;
    }
}
void insert(int loc)
{
    cnt[a[loc]]++;
    //printf("l=%d r=%d\n",L,R);
    ret=ret*(R-L+1)%mod;
    ret=ret*inv[cnt[a[loc]]]%mod;
    //printf("ret=%lld\n",ret);
}
void erase(int loc)
{
    ret=ret*cnt[a[loc]]%mod;
    ret=ret*inv[R-L+1]%mod;
    cnt[a[loc]]--;
}
int main()
{
    get_inverse(30000,mod);
    for(scanf("%d",&t);t--;)
    {
        scanf("%d %d",&n,&m);
        F(i,1,n) scanf("%d",a+i);
        len=sqrt(n);
        F(i,1,m)
        {
            int left,right;
            scanf("%d %d",&left,&right);
            e[i]=node(left,right,i);
        }
        sort(e+1,e+1+m);
        L=1,R=0;
        ret=1;
        mem(ans,0);mem(cnt,0);
        //F(i,1,n) printf("%lld%c",inv[i],i==n?'\n':' ');
        F(i,1,m)
        {
            //printf("ret1=%lld\n",ret);
            while(R<e[i].r) insert(++R);
            while(L>e[i].l) insert(--L);
            while(R>e[i].r) erase(R--);
            while(L<e[i].l) erase(L++);
            ans[e[i].id]=ret;
            //printf("ret2=%lld\n",ret);
        }
        F(i,1,m) printf("%lld\n",ans[i]);
    }
    return 0;
}
//ac
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define F(i,a,b) for(int i=a;i<=b;++i)
#define R(i,a,b) for(int i=a;i<b;++i)
#define mem(a,b) memset(a,b,sizeof(a))
const ll mod = 1000000007;
int t,n,m,len,L,R;
int a[30030],cnt[30030];
ll ans[30030],inv[30030];
ll ret;
struct node
{
    int l,r,id,block;
    node(){}
    node(int _l,int _r,int _id):l(_l),r(_r),id(_id){block=l/len;}
    bool operator<(const node &p)const
    {
        return block==p.block?r<p.r:block<p.block;
    }
}e[30030];
ll pow_mod(ll a,ll p)
{
    ll ans=1;
    for(ll ret=a;p;p>>=1,ret=ret*ret%mod) if(p&1) ans=ans*ret%mod;
    return ans%mod;
}
void insert(int loc)
{
    cnt[a[loc]]++;
    //printf("l=%d r=%d\n",L,R);
    ret=ret*(R-L+1)%mod;
    ret=ret*inv[cnt[a[loc]]]%mod;
    //printf("ret=%lld\n",ret);
}
void erase(int loc)
{
    ret=ret*cnt[a[loc]]%mod;
    ret=ret*inv[R-L+1]%mod;
    cnt[a[loc]]--;
}
int main()
{
    F(i,1,30000) inv[i]=pow_mod(i,mod-2);
    for(scanf("%d",&t);t--;)
    {
        scanf("%d %d",&n,&m);
        F(i,1,n) scanf("%d",a+i);
        len=sqrt(n);
        F(i,1,m)
        {
            int left,right;
            scanf("%d %d",&left,&right);
            e[i]=node(left,right,i);
        }
        sort(e+1,e+1+m);
        ret=1;
        mem(ans,0);mem(cnt,0);
        L=1;R=0;
        //F(i,1,n) printf("%lld%c",inv[i],i==n?'\n':' ');
        F(i,1,m)
        {
            //printf("ret1=%lld\n",ret);
            while(R<e[i].r) {++R;insert(R);}
            while(L>e[i].l) {--L;insert(L);}
            while(R>e[i].r) {erase(R);R--;}
            while(L<e[i].l) {erase(L);L++;}
            ans[e[i].id]=ret;
            //printf("ret2=%lld\n",ret);
        }
        F(i,1,m) printf("%lld\n",ans[i]);
    }
    return 0;
}
posted @ 2017-06-29 12:33  遗风忘语  阅读(306)  评论(0编辑  收藏  举报