[学习笔记]莫队

补充:戳这里

1、NPY and girls

题意简述:给定一个长度为 \(n\) 的序列,每次给定一个区间 \([l,r]\),求 \((r-l+1)!/(count(1)!\times count(2)!\times ...\times count(n)!)\)

先预处理出阶乘和阶乘的乘法逆元,然后每次更新除掉原来的数乘上后来的数就好了

\(Code\ Below:\)

#include <cstdio>
#include <cctype>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=30000+10;
const int p=1e9+7;
int n,m,a[maxn],cnt[maxn],ans[maxn],farc[maxn],inv[maxn],blo,now;

struct Query{
	int l,r,id;
}q[maxn];

bool cmp(Query a,Query b){
	if((a.l-1)/blo!=(b.l-1)/blo)
		return (a.l-1)/blo<(b.l-1)/blo;
	return a.r<b.r;
}

inline int read(){
	register int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return (f==1)?x:-x;
}

int fast_pow(int a,int b){
	int ret=1;
	for(;b;b>>=1,a=(ll)a*a%p)
		ret=(ll)ret*(b&1?a:1)%p;
	return ret;
}

inline void add(int x){
	if(cnt[a[x]]) now=(ll)now*farc[cnt[a[x]]]%p;
	now=(ll)now*inv[++cnt[a[x]]]%p;
}
inline void del(int x){
	now=(ll)now*farc[cnt[a[x]]--]%p;
	if(cnt[a[x]]) now=(ll)now*inv[cnt[a[x]]]%p;
}

int main()
{
	farc[1]=1;
	for(int i=2;i<=maxn-10;i++) farc[i]=(ll)farc[i-1]*i%p;
	inv[maxn-10]=fast_pow(farc[maxn-10],p-2);
	for(int i=maxn-11;i>=1;i--) inv[i]=(ll)inv[i+1]*(i+1)%p;
	int T=read();
	while(T--){
		memset(cnt,0,sizeof(cnt));
		n=read(),m=read();blo=sqrt(n);
		for(int i=1;i<=n;i++) a[i]=read(); 
		for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
		sort(q+1,q+m+1,cmp);
		int L=1,R=0;now=1;
		for(int i=1;i<=m;i++){
			while(R<q[i].r) add(++R);
			while(R>q[i].r) del(R--);
			while(L<q[i].l) del(L++);
			while(L>q[i].l) add(--L);
			ans[q[i].id]=(ll)farc[q[i].r-q[i].l+1]*now%p;
		}
		for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
	}
	return 0;
}

2、Lucky

类似一个不简单的询问的处理方式

\(Code\ Below:\)

#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=100000+10;
int n,m,k,a[maxn],b[maxn<<1],c[maxn<<1],tot,blo;ll ans[maxn],now;

struct Query{
	int l,r,v,id;
}q[maxn<<2];

bool cmp(Query a,Query b){
	if((a.l-1)/blo!=(b.l-1)/blo)
		return (a.l-1)/blo<(b.l-1)/blo;
	return a.r<b.r; 
}

inline int read(){
	register int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return (f==1)?x:-x;
}

inline void addb(int x){now+=(ll)c[k-a[x]];b[a[x]]++;}
inline void delb(int x){now-=(ll)c[k-a[x]];b[a[x]]--;}
inline void addc(int x){now+=(ll)b[k-a[x]];c[a[x]]++;}
inline void delc(int x){now-=(ll)b[k-a[x]];c[a[x]]--;}

inline void add(int l,int r,int v,int id){
	q[++tot].l=l;q[tot].r=r;q[tot].v=v;q[tot].id=id;
}

int main()
{
	while(cin>>n>>k){
		memset(b,0,sizeof(b));
		memset(c,0,sizeof(c));
		memset(ans,0,sizeof(ans));
		tot=now=0;blo=sqrt(n);
		for(int i=1;i<=n;i++) a[i]=read();
		m=read();
		int l1,r1,l2,r2;
		for(int i=1;i<=m;i++){
			l1=read(),r1=read(),l2=read(),r2=read();
			add(r1,r2,1,i);
			if(l1>1) add(l1-1,r2,-1,i);
			if(l2>1) add(r1,l2-1,-1,i);
			if(l1>1&&l2>1) add(l1-1,l2-1,1,i);
		}
		sort(q+1,q+tot+1,cmp);
		int L=0,R=0;
		for(int i=1;i<=tot;i++){
			while(L<q[i].l) addb(++L);
			while(L>q[i].l) delb(L--);
			while(R<q[i].r) addc(++R);
			while(R>q[i].r) delc(R--);
			ans[q[i].id]+=(ll)q[i].v*now;
		}
		for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
	}
	return 0;
}
posted @ 2018-11-22 19:43  Owen_codeisking  阅读(198)  评论(0编辑  收藏  举报