Hdu 5145 NPY and girls

 一个很普通的莫队题+可重集排列

莫队的说明网上已经很多了,我就不献丑了


直接来考虑添加端点或者删除端点的情况吧

添加 就是分子乘区间长度,分母乘当前位置的数的个数,然后更新数的个数

删除 就是分母乘区间长度,分子乘当前位置的数的个数,同样更新一下数的个数


莫队的我没有注意到的一个trick是

转移区间的时候优先更新右端点,然后左端点,否则可能出现右端点在左端点左边的情况


#include
#include
#include
#include
using namespace std;

#define LL long long

const int maxn = 31234;
const LL mod = 1000000007;

struct Ask{
    int l,r;
    int id;
    LL ans;
    void init(int i){
        scanf("%d %d",&l,&r);
        id = i;
    }
};

Ask ask[maxn];
int unit;

bool cmpmo(Ask a,Ask b){
    if(a.l / unit != b.l / unit)
        return a.l < b.l;
    return a.r < b.r;
}

bool cmpid(Ask a,Ask b){
    return a.id < b.id;
}

LL cnt[maxn];
int arr[maxn];

LL rever[maxn];

LL powerMod(LL x,LL n,LL mod){
    LL ret = 1;
    while(n){
        if(n&1) (ret *= x) %= mod;
        (x *= x) %= mod;
        n >>=1;
    }
    return ret;
}

LL rev(int x){
    if(rever[x] != -1)
        return rever[x];
    return rever[x] = powerMod(x,mod-2,mod);
}

LL siz;

LL renew(LL ans,int pos,bool adder){
    LL & x = cnt[arr[pos]];
    if(adder){
        x++;
        siz++;
        (ans *= siz) %= mod;
        (ans *= rev(x)) %= mod;
    }
    else{
        (ans *= x) %= mod;
        (ans *= rev(siz)) %= mod;
        siz--;
        x--;
    }
    return ans;
}

int main(){
    int T;
    int n,m;
    memset(rever,-1,sizeof(rever));
    scanf("%d",&T);
    while(T-- && ~scanf("%d %d",&n,&m)){
        unit = (int)sqrt(n*1.0);
        for(int i=1;i<=n;i++){
            scanf("%d",&arr[i]);
        }
        for(int i=0;i


你可能感兴趣的:(莫队算法,--数据结构---)