http://acm.hdu.edu.cn/showproblem.php?pid=5145
初探莫队,就是离线排序后的暴力,但是效率大大提高,中间要除法取模,所以用到了逆元。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #define LL long long #define MOD 1000000007 using namespace std; int a[30005],num[30005],n,m,sizee; LL ans[30005],inv[30005]; struct node { int l,r,num,belong; }query[30005]; void init() { for(int i = 1;i <= 30000;i++) { LL temp = 1,x = i; int pow = MOD-2; while(pow) { if(pow%2) temp = temp*x%MOD; x = x*x%MOD; pow /= 2; } inv[i] = temp; } } int cmp(node x,node y) { if(x.belong == y.belong) return x.r < y.r; return x.l<y.l; } int main() { init(); int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); sizee = sqrt(n); for(int i = 1;i <= n;i++) scanf("%d",&a[i]); for(int i = 1;i <= m;i++) { scanf("%d%d",&query[i].l,&query[i].r); query[i].num = i; query[i].belong = (query[i].l-1)/sizee+1; } sort(query+1,query+1+m,cmp); memset(num,0,sizeof(num)); int ll = 1,rr = 1; LL now = 1; num[a[1]]++; for(int i = 1;i <= m;i++) { while(rr < query[i].r) { rr++; num[a[rr]]++; now = now*(rr-ll+1)%MOD*inv[num[a[rr]]]%MOD; } while(ll > query[i].l) { ll--; num[a[ll]]++; now = now*(rr-ll+1)%MOD*inv[num[a[ll]]]%MOD; } while(ll < query[i].l) { now = now*num[a[ll]]%MOD*inv[rr-ll+1]%MOD; num[a[ll]]--; ll++; } while(rr > query[i].r) { now = now*num[a[rr]]%MOD*inv[rr-ll+1]%MOD; num[a[rr]]--; rr--; } ans[query[i].num] = now; } for(int i = 1;i <= m;i++) printf("%lld ",ans[i]); } return 0; }