数据结构|20200502省选模拟赛 C (莫队+数值分治)

【数据结构|20200502省选模拟赛 C (莫队+数值分治)】数据结构|20200502省选模拟赛 C (莫队+数值分治)
文章图片



题解 或许这就是人生吧
这题似乎比[Ynoi2015]此时此刻的光辉更毒瘤
一些数的子集的gcd很难直接计算
我们就来考虑每种质因子的贡献
则答案就是
数据结构|20200502省选模拟赛 C (莫队+数值分治)
文章图片

f[p^k]表示在这段数中有多少个子集的gcd被p^k整除
显然f[p^k]=2^g[p^k]-1,g[p^k]表示这段区间中有多少个数被p^k整除
稍微变换一下形式
数据结构|20200502省选模拟赛 C (莫队+数值分治)
文章图片

数据结构|20200502省选模拟赛 C (莫队+数值分治)
文章图片

数据结构|20200502省选模拟赛 C (莫队+数值分治)
文章图片

最后的这个形式就比较简单
我们如果直接用莫队,时间复杂度将会是O(n*sqrt(m)*(sqrt(w)/ln(w))*logw+m)(有一个枚举质因子以及其幂次k复杂度和一个快速幂复杂度)
最后的那个logw可以通过预处理来消掉
至于sqrt(w)/ln(w)
我们可以对数值进行分治
把<=sqrt(w)的质数单独拿出来,把它们的可能的所有幂次求出来,做一个前缀和
就可以把这一部分的复杂度分一点到后面的O(m)
>sqrt(w)的质数由于每个数只有一个,所以可以O(1)加入
所以复杂度就平衡为O(n*sqrt(m)+m*2sqrt(sqrt(w))/ln(w))
代码:(细节超多)(vector要reverse否则会爆内存)

#include #include #include #include using namespace std; inline int gi() { char c; int num=0,flg=1; while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1; while(c>='0'&&c<='9'){num=num*10+c-48; c=getchar(); } return num*flg; } #define N 100005 #define D 331 const int mod=998244353; int n,m,a[N]; int prime[N],tot; bool vis[N]; int num[N]; int sum[180][N],pr[180],scnt; //prework: calculate the pw and inv of prime>=sqrt(n) int tong[N]; vector pw[N],inv[N]; int ksm(int x,int y) { int ret=1; while(y){ if(y&1)ret=1ll*ret*x%mod; y>>=1; x=1ll*x*x%mod; } return ret; } void shai() { int i,j,k; vis[1]=1; for(i=2; i<=100000; i++){ if(!vis[i])prime[++tot]=i; for(j=1; j<=tot; j++){ int tmp=i*prime[j]; if(tmp>100000)break; vis[tmp]=1; if(i%prime[j]==0)break; } } for(i=1; i<=tot; i++){ int x=prime[i]; if(x<=D){ for(j=x; j<=100000; j*=x){ pr[++scnt]=x; for(k=1; k<=n; k++){ sum[scnt][k]=sum[scnt][k-1]; if(a[k]%j==0)sum[scnt][k]++; } if(j==x){ pw[x].reserve(sum[scnt][n]+1); pw[x].push_back(x); for(k=1; k<=sum[scnt][n]; k++) pw[x].push_back(1ll*pw[x][k-1]*pw[x][k-1]%mod); for(k=1; k<=sum[scnt][n]; k++) pw[x][k]=1ll*pw[x][k]*pw[x][k-1]%mod; } } } } for(i=1; i<=n; i++){ for(j=1; j<=tot; j++){ if(prime[j]>D)break; while(a[i]%prime[j]==0) a[i]/=prime[j]; } tong[a[i]]++; } for(i=1; i<=100000; i++){ int x=i; if(tong[x]){ pw[x].reserve(tong[x]+1); inv[x].reserve(tong[x]+1); pw[x].push_back(x); inv[x].push_back(ksm(x,mod-2)); for(j=1; j<=tong[x]; j++){ pw[x].push_back(1ll*pw[x][j-1]*pw[x][j-1]%mod); inv[x].push_back(1ll*inv[x][j-1]*inv[x][j-1]%mod); } } } } int bel[N]; struct node{ int l,r,id; bool operator < (const node &t)const{ int f=bel[l]; return ft.r))); } }q[N]; int cnt[N],ans,mul; void add(int x) { if(x==1)return; ans=1ll*ans*pw[x][cnt[x]]%mod; cnt[x]++; } void del(int x) { if(x==1)return; cnt[x]--; ans=1ll*ans*inv[x][cnt[x]]%mod; } int lan[N]; int main() { freopen("C.in","r",stdin); freopen("C.out","w",stdout); int i,j,l,r; n=gi(); m=gi(); for(i=1; i<=n; i++){a[i]=gi(); bel[i]=(i-1)/D+1; } for(i=1; i<=m; i++){q[i].l=gi(); q[i].r=gi(); q[i].id=i; } sort(q+1,q+m+1); shai(); ans=mul=1; l=q[1].l; r=q[1].r; for(i=q[1].l; i<=q[1].r; i++)add(a[i]); for(i=1; i<=scnt; i++) if(sum[i][r]-sum[i][l-1]>0) mul=1ll*mul*pw[pr[i]][sum[i][r]-sum[i][l-1]-1]%mod; lan[q[1].id]=1ll*ans*mul%mod; for(i=2; i<=m; i++){ while(rq[i].l)l--,add(a[l]); while(r>q[i].r)del(a[r]),r--; while(l0) mul=1ll*mul*pw[pr[j]][sum[j][r]-sum[j][l-1]-1]%mod; lan[q[i].id]=1ll*ans*mul%mod; } for(i=1; i<=m; i++) printf("%d\n",lan[i]); }









    推荐阅读