NPY and girls
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5145
莫队算法
注意到没有修改区间的操作,使用莫队算法:将整个区间分成若干个块,将询问区间按块优先升序排序,同块内按区间右界升序排序,添加一个元素,满足条件的值sum就变为sum=(sum*times[a[r]]/(r-l+1));减少一个值同理。从第一个区间一直推到最后一个区间即可。(之前TLE一直以为是区间大小的问题,现在发现是这句话while(x<0)x+=M,不过因为这题M比较大,改改区间居然被我水过去了...)
代码如下:
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 #define N 30005 6 #define M 1000000007 7 #define LL long long 8 #define B 250/**((int)sqrt((double)n)) sqrt(n) will be TLE**/ 9 #define mst(x) memset(x,0,sizeof(x)) 10 using namespace std; 11 LL times[N]; 12 LL T,n,m,x,y; 13 LL a[N]; 14 struct nod{ 15 LL l,r,no,value; 16 }q[N]; 17 LL exGCD(LL a,LL b){ 18 if(b==0){ 19 x=1; 20 y=0; 21 return a; 22 } 23 LL r=exGCD(b,a%b); 24 LL tmp=x; 25 x=y; 26 y=tmp-(a/b)*y; 27 return r; 28 } 29 bool cmp_by_range(nod x,nod y){ 30 if(x.l/B==y.l/B){ 31 return x.r<y.r; 32 }else return (x.l/B<y.l/B); 33 } 34 bool cmp_by_no(nod x,nod y){ 35 return x.no<y.no; 36 } 37 void init(){ 38 mst(times); 39 scanf("%I64d%I64d",&n,&m); 40 for(LL i=0;i<n;++i) 41 scanf("%I64d",&a[i]); 42 for(LL i=0;i<m;++i){ 43 LL l,r; 44 scanf("%I64d%I64d",&l,&r); 45 l--,r--; 46 q[i].l=l; 47 q[i].r=r; 48 q[i].no=i; 49 q[i].value=0; 50 } 51 sort(q,q+m,cmp_by_range); 52 } 53 void solve(){ 54 LL l=q[0].l,r=q[0].r,sum=1; 55 times[a[l]]++; 56 for(LL i=l+1;i<=r;++i){ 57 times[a[i]]++; 58 exGCD(times[a[i]],M); 59 while(x<0)x+=M; 60 sum=((sum*(i-l+1))%M*x)%M; 61 } 62 q[0].value=sum; 63 for(LL i=1;i<m;++i){ 64 //l=q[i-1].l,r=q[i-1].r; 65 while(r<q[i].r){ 66 r++; 67 times[a[r]]++; 68 exGCD(times[a[r]],M); 69 while(x<0)x+=M; 70 sum=((sum*(r-l+1))%M*x)%M; 71 } 72 while(r>q[i].r){ 73 exGCD((r-l+1),M); 74 while(x<0)x+=M; 75 sum=((sum*times[a[r]])%M*x)%M; 76 times[a[r]]--; 77 r--; 78 } 79 while(l<q[i].l){ 80 exGCD((r-l+1),M); 81 while(x<0)x+=M; 82 sum=((sum*times[a[l]])%M*x)%M; 83 times[a[l]]--; 84 l++; 85 } 86 while(l>q[i].l){ 87 l--; 88 times[a[l]]++; 89 exGCD(times[a[l]],M); 90 while(x<0)x+=M; 91 sum=((sum*(r-l+1)%M)*x)%M; 92 } 93 q[i].value=sum; 94 } 95 } 96 int main(void){ 97 scanf("%I64d",&T); 98 while(T--){ 99 init(); 100 solve(); 101 sort(q,q+m,cmp_by_no); 102 for(LL i=0;i<m;++i) 103 printf("%I64d ",q[i].value); 104 } 105 }