zoukankan      html  css  js  c++  java
  • 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
    ",L,R);
        ret=ret*(R-L+1)%mod;
        ret=ret*inv[cnt[a[loc]]]%mod;
        //printf("ret=%lld
    ",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?'
    ':' ');
            F(i,1,m)
            {
                //printf("ret1=%lld
    ",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
    ",ret);
            }
            F(i,1,m) printf("%lld
    ",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
    ",L,R);
        ret=ret*(R-L+1)%mod;
        ret=ret*inv[cnt[a[loc]]]%mod;
        //printf("ret=%lld
    ",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?'
    ':' ');
            F(i,1,m)
            {
                //printf("ret1=%lld
    ",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
    ",ret);
            }
            F(i,1,m) printf("%lld
    ",ans[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    2018-08-25多线程Thread类+Runnable接口+线程的6种状态
    2018-08-24Properties类+序列化+反序列化+FileUtils+FilenameUtils
    2018-08-22字节字符转换流InputStreamReader+OutputStreamWriter+缓冲流Buffered+newLine换行方法
    2018-08-21文件字节输出流OutputStream+文件字节输入流InputStream+字符输出流FileReader+字符输出流FileWriter
    2018-08-20内容IO流中的File类+文件过滤器FileFilter+递归
    List接口方法、LinkedList方法、Vector集合、Set接口下HashSet、LinkedHashSet集合、HashCode()+equals()方法对于Set接口判断重复的详细细节
    集合之Collection接口AND Iterator迭代器 AND 增强for AND 泛型
    面向对象测试题
    基本类型包装类之system类
    Date
  • 原文地址:https://www.cnblogs.com/chendl111/p/7093835.html
Copyright © 2011-2022 走看看