hdu5145 莫队算法
这题说的是个了n个数字 然后 在L 和R 区间内的数字的排列有多少种方案,
这里我们通过 将 这n长度的字符串 分成sqrt(n) 块然后 一个属性 他们的l 属于 那个快 以这个为第一关键字 ,然后 在按照R 为 第二个关键字,然后sort 每个查询区间
我们知道 当L他们属于一块内的时候 , R 是逐渐递增的 ,那么 转移了 sqrt(n)*a+n个 然后以此方案接近复杂度接近n^(1.5)
#include <iostream> #include <algorithm> #include <string.h> #include <vector> #include <cstdio> #include <cmath> using namespace std; typedef long long LL; const int maxn = 30005; const LL mod = 1000000007; struct seg{ int L,R,id; }P[maxn]; int b[maxn]; void gcd(LL a, LL b, LL &d, LL &x, LL &y ){ if(b==0){ d=a; x=1; y=0; }else{ gcd(b,a%b,d,y,x); y-=x*(a/b); } } LL inv( LL a){ LL d, x,y; gcd(a,mod,d,x,y); return d==1?(x+mod)%mod:-1; } LL A[maxn],ans[maxn],num[maxn],aa,niA[maxn]; int C[maxn]; bool cmp(seg A, seg B){ return b[A.L]==b[B.L]?A.R<B.R:b[A.L]<b[B.L]; } void update(int x, int add){ aa= (aa * niA[ num[x] ] )%mod; num[x]+=add; aa= (aa * A[num[x] ] )%mod; } void solve(int m){ memset(num,0,sizeof(num)); aa=1; LL L=1, R=0; for(int i=0; i<m; i++){ while(R<P[i].R){ R++; update(C[R],1); } while(R>P[i].R){ update(C[R],-1);R--; } while(L<P[i].L){ update(C[L],-1);L++; } while(L>P[i].L){ L--; update(C[L],1); } ans[ P[i].id ]=(inv(aa)*A[ P[i].R-P[i].L+1 ])%mod; } for(int i=0; i<m; i++){ printf("%I64d\n",ans[i]); } } int main() { A[0]=1; niA[0]=inv(1); for(LL i=1; i<maxn-1; i++){ A[i]=(A[i-1]*i)%mod; niA[i] = inv(A[i]); } int cas; scanf("%d",&cas); for(int cc=1; cc<=cas; ++cc){ int n,m; scanf("%d%d",&n,&m); int boloc=sqrt(n+0.5); for(int i=1; i<=n; i++){ b[i]=(i-1)/boloc+1; } for(int i=1; i<=n; i++)scanf("%d",&C[i]); for(int i=0; i<m; i++){ P[i].id=i; scanf("%d%d",&P[i].L,&P[i].R); } sort(P,P+m,cmp); solve(m); } return 0; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。