珂朵莉的约数(牛客练习赛9)
链接:https://www.nowcoder.com/acm/contest/40/F
来源:牛客网
珂朵莉给你一个长为n的序列,有m次查询
每次查询给两个数l,r
设s为区间[l,r]内所有数的乘积
求s的约数个数mod 1000000007
输入描述:
第一行两个正整数n,m
第二行一个长为n的序列
之后m行每行两个数l和r
输出描述:
对于每个询问,输出一个整数表示答案
备注:
对于100%的数据,有n , m <= 100000 , a[i] <= 1000000
题解:对于1 - 1e6 范围的数他大于1e3的素数因子最多只有一个,我们可以用莫队来维护他,但对于1 - 1e3的来说最多有168个素数因子,所以用一个前缀和,来解决
调了一天的莫队,wawawawa 很迷茫,然后将那4个while 顺序转换一下,然后就A了。。。。。。。。(真是搞不清楚为啥会 Wa)
AC code:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5 + 10; const int MOD = 1e9+7; int prime[1007],tot;bool vis[1007]; ll inv[N],ans[N],ant; int Be[N],a[N],sum[N*10],pre[N][170]; // sum存 在区间内 > 1000 的素数的个数 void init() { tot = 0; for(int i = 2;i <= 1000;i++) { if(vis[i]) continue; prime[tot++] = i; for(int j = i + i; j <= 1000; j += i ) vis[j] = 1; } } struct Mo{ int l,r,id; }Q[N]; int cmp(Mo a,Mo b){ return Be[a.l] == Be[b.l] ? a.r < b.r : a.l < b.l;} void add(int pos) { if(a[pos] == 1) return; ant = ant*inv[1+sum[a[pos]]]%MOD; sum[a[pos]]++; ant = ant*(1+sum[a[pos]])%MOD; } void del(int pos) { if(a[pos] == 1) return; ant = ant*inv[1+sum[a[pos]]]%MOD; sum[a[pos]]--; ant = ant*(1+sum[a[pos]])%MOD; } int main() { int n,m; init(); scanf("%d%d",&n,&m); inv[0] = inv[1] = 1; for(int i=2;i<=n+1;i++) inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD ; // 逆元筛 int len = sqrt(n); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); Be[i] = i/len; for(int j = 0;j < tot;j++) { pre[i][j] = pre[i-1][j]; while(a[i] % prime[j] == 0) { pre[i][j]++; a[i] /= prime[j]; } } } for(int i = 1;i <= m;i++) scanf("%d%d",&Q[i].l,&Q[i].r),Q[i].id = i; sort(Q+1,Q+m+1,cmp); memset(sum,0,sizeof(sum)); ant = 1; int l = 1,r = 0; for(int i = 1;i <= m;i++) { while(r < Q[i].r) add(r+1),r++; while(r > Q[i].r) del(r),r--; while(l < Q[i].l) del(l),l++; while(l > Q[i].l) add(l-1),l--; ll res = 1; for(int j=0;j<tot;j++) res=1ll*res*(pre[r][j]-pre[l-1][j]+1)%MOD; ans[Q[i].id] = 1ll*ant*res %MOD; } for(int i = 1;i <= m;i++) printf("%lld\n",ans[i]); return 0; }