[Ynoi2015]此时此刻的光辉
Posted mrsrz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Ynoi2015]此时此刻的光辉相关的知识,希望对你有一定的参考价值。
题目大意:
给定一个序列,每次询问一段区间的数的乘积的约数个数。
解题思路:
在太阳西斜的这个世界里,置身天上之森。等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去、逐渐消逝的未来。我回来了,纵使日薄西山,即便看不到未来,此时此刻的光辉,盼君勿忘。————世界上最幸福的女孩
我永远喜欢珂朵莉。
---
(10^9)以内的数最多有10个**不同的**质因子。
考虑对其质因数分解。
由于值域范围过大,考虑使用Pollard-Rho算法。
这里普通的Pollard-Rho算法可能会TLE。如果你的代码能通过模板题,那基本上没问题(~~窝反正直接把以前写的板子拉过来然后调了调参~~)。
之后,你就会得到最多(10n)个不同的质因数。对其进行离散化,开桶记录。
然后上莫队,对于每次指针的偏移,把它所有的质因数加到桶里,同时维护约数个数即可。
这部分时间复杂度(O(10nsqrt n)),加上上面的质因数分解的玄学期望复杂度,只能获得82分的好成绩。
---
我们考虑把每个数(1000)以内的质因子先取出来((1000)以内共168个质数),然后,对其做前缀和,记录前缀的出现次数。
然后,由于(1001^3>10^9),所以每个数剩下最多不超过2个质因子。这部分用Pollard_Rho找即可。
然后莫队的时候,对于前面168个质数就可以不用维护,直接用前缀和。
而对于后面的大质因子,再离散化处理即可。由于每个数最多两个质因子,所以常数就小了很多。
而由于筛掉了很多小的质因子,Pollard_Rho的速度也会变快。然后就足以通过此题。
C++ Code:
// luogu-judger-enable-o2 #include<cctype> #include<cstdio> #include<cstdlib> #include<algorithm> #include<vector> #include<cstring> #define ctz __builtin_ctz using namespace std; #ifdef ONLINE_JUDGE struct istream{ char buf[23333333],*s; inline istream(){ buf[fread(s=buf,1,23333330,stdin)]=‘ ‘; fclose(stdin); } inline istream&operator>>(int&d){ d=0; for(;!isdigit(*s);++s); while(isdigit(*s)) d=(d<<3)+(d<<1)+(*s++^‘0‘); return*this; } }cin; struct ostream{ char buf[8000005],*s; inline ostream(){s=buf;} inline ostream&operator<<(int d){ if(!d){ *s++=‘0‘; }else{ static int w; for(w=1;w<=d;w*=10); for(;w/=10;d%=w)*s++=d/w^‘0‘; } return*this; } inline ostream&operator<<(const char&c){*s++=c;return*this;} inline void flush(){ fwrite(buf,1,s-buf,stdout); s=buf; } inline~ostream(){flush();} }cout; #else #include<iostream> #endif int pri[170],cct=0,sum[100005][170],num[1005]; void sieve(){ for(int i=2;i<=1000;++i)num[i]=1; for(int i=2;i<=1000;++i) if(num[i]){ pri[num[i]=++cct]=i; for(int j=i<<1;j<=1000;j+=i)num[j]=0; } } using LoveLive=long long; vector<int>tj; const int pr[]={2,3,5,24251,61,19260817}; int gcd(int a,int b){ if(!a||!b)return a|b; int t=ctz(a|b); a>>=ctz(a); do{ b>>=ctz(b); if(a>b)swap(a,b); b-=a; }while(b); return a<<t; } inline int power(int a,int b,const int&md){ int ans=1; for(;b;b>>=1){ if(b&1)ans=(LoveLive)ans*a%md; a=(LoveLive)a*a%md; } return ans; } bool miller_rabin(int p){ if(p==2)return 1; LoveLive b=p-1; int t=0; while(!(b&1))b>>=1,++t; for(int i:pr){ int r=power(i%(p-2)+2,b,p); if(r==1||r==p-1)continue; bool ok=true; for(int j=1;j<=t&&ok;++j){ r=(LoveLive)r*r%p; if(r==p-1)ok=false; } if(ok)return false; } return true; } void pollard_rho(int&n,int c){ int k=2,x=rand()%(n-1)+1,y=x,q=1,t=1; for(;;k<<=1,y=x,q=1){ for(int i=1;i<=k;++i){ x=((LoveLive)x*x%n+c)%n; q=(LoveLive)q*abs(x-y)%n; if(!(i&63)){ t=gcd(q,n); if(t>1)break; } } if(t>1||(t=gcd(q,n))>1)break; } n=t; } void find(int n,int c){ if(n==1)return; if(miller_rabin(n)){tj.push_back(n);return;} int p=n; while(p>=n)pollard_rho(p,c--); while(n%p==0)n/=p; find(n,23333),find(p,23333); } #define N 100005 const int md=19260817; int n,m,a[N],inv[N],cnt[N],tot[N*2],now=1,ans[N]; int p[N][3],s[N][3]; vector<int>lr; struct que{ static const int siz=317; int l,r,id; inline bool operator<(const que&rhs)const{ return((l/siz!=rhs.l/siz)?(l<rhs.l):r<rhs.r); } }q[N]; inline void add(int id){ for(register int i=1;i<=cnt[id];++i) now=now*1LL*inv[tot[p[id][i]]]%md*(tot[p[id][i]]+s[id][i])%md,tot[p[id][i]]+=s[id][i]; } inline void del(int id){ for(register int i=1;i<=cnt[id];++i) now=now*1LL*inv[tot[p[id][i]]]%md*(tot[p[id][i]]-s[id][i])%md,tot[p[id][i]]-=s[id][i]; } int main(){ srand(19260817); sieve(); inv[1]=1; for(int i=2;i<=1e5;++i)inv[i]=(md-md/i)*1LL*inv[md%i]%md; cin>>n>>m; for(int i=1;i<=n;++i){ tj.clear(); cin>>a[i]; memcpy(sum[i],sum[i-1],sizeof*sum); for(int j=1;j<=cct&&pri[j]*pri[j]<=a[i];++j) while(!(a[i]%pri[j])){ ++sum[i][j]; a[i]/=pri[j]; } if(a[i]>1){ if(a[i]<=pri[cct]){ ++sum[i][num[a[i]]]; continue; } find(a[i],23333); for(int it:tj) p[i][++cnt[i]]=it,lr.push_back(it); int P=a[i]; for(int j=1;j<=cnt[i];++j){ const int&m=p[i][j]; while(P%m==0){ ++s[i][j]; P/=m; } } } } sort(lr.begin(),lr.end()); lr.erase(unique(lr.begin(),lr.end()),lr.end()); for(int i=1;i<=n;++i) for(int j=1;j<=cnt[i];++j)p[i][j]=lower_bound(lr.begin(),lr.end(),p[i][j])-lr.begin(); for(int i=1;i<=m;++i)cin>>q[q[i].id=i].l>>q[i].r; sort(q+1,q+m+1); for(int i=0;i<n*2;++i)tot[i]=1; for(int i=1,l=1,r=0;i<=m;++i){ while(r<q[i].r)add(++r); while(l>q[i].l)add(--l); while(r>q[i].r)del(r--); while(l<q[i].l)del(l++); int&out=ans[q[i].id];out=now; for(int j=1;j<=cct;++j) out=1LL*out*(sum[r][j]-sum[l-1][j]+1)%md; } for(int i=1;i<=m;++i) cout<<ans[i]<<‘ ‘; return 0; }
以上是关于[Ynoi2015]此时此刻的光辉的主要内容,如果未能解决你的问题,请参考以下文章