珂朵莉的约数
來源:牛客網(wǎng):
題目描述
珂朵莉給你一個長為n的序列,有m次查詢
每次查詢給兩個數(shù)l,r
設(shè)s為區(qū)間[l,r]內(nèi)所有數(shù)的乘積
求s的約數(shù)個數(shù)mod 1000000007
輸入描述:
第一行兩個正整數(shù)n,m
第二行一個長為n的序列
之后m行每行兩個數(shù)l和r
輸出描述:
對于每個詢問,輸出一個整數(shù)表示答案
示例1
輸入
復(fù)制
輸出
復(fù)制
備注:
對于100%的數(shù)據(jù),有n , m <= 100000 , a[i] <= 1000000
題解:
莫隊+數(shù)論(約數(shù)個數(shù))
很容易看出是莫隊的題,個人認(rèn)為難點在于求約數(shù)的個數(shù),常規(guī)的求約束的個數(shù)肯定不行,有一個叫約束個數(shù)定理的東西
任何一個大于1的n都可以分解:
n=p1a1×p2a2×p3a3*…*pkak,p為素數(shù)
而n的約數(shù)的個數(shù)就是(a1+1)(a2+1)(a3+1)…(ak+1)
再看一下本題數(shù)據(jù),對于不超過1000的素數(shù)我們可以直接維護每個素數(shù)的冪指數(shù)+1的前綴乘積(共168個),而超過1000的素因數(shù)最多也就一個。代碼中ant用來記錄1000之外的素因子,res用來記錄1000之內(nèi)的每個素數(shù)的冪指數(shù)+ 1 +1+1的前綴乘積
線性篩就是每一次被最小素因數(shù)給篩出來,所以用線性篩來計算因數(shù)和。因為題目要mod,所以我們還要線性預(yù)處理逆元,方便后面使用
具體線性篩如何求因數(shù)和可以看其他博客講解
具體代碼如下
代碼:
#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存 在區(qū)間內(nèi) > 1000 的素數(shù)的個數(shù) 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)//如果這個質(zhì)數(shù)是因子 {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; }總結(jié)
- 上一篇: 如何修复手机电池 这样操作焕然一新
- 下一篇: 中国诺贝尔奖排名 中国诺贝尔获得者有哪些