題解
或許這就是人生吧
這題似乎比[Ynoi2015]此時此刻的光輝更毒瘤
一些數的子集的gcd很難直接計算
我們就來考慮每種質因子的貢獻
則答案就是
f[p^k]表示在這段數中有多少個子集的gcd被p^k整除
顯然f[p^k]=2^g[p^k]-1,g[p^k]表示這段區間中有多少個數被p^k整除
稍微變換一下形式
最後的這個形式就比較簡單
我們如果直接用莫隊,時間複雜度將會是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<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
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<int> 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 f<bel[t.l]||(f==bel[t.l]&&(((f&1)&&r<t.r)||(!(f&1)&&r>t.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(r<q[i].r)r++,add(a[r]);
while(l>q[i].l)l--,add(a[l]);
while(r>q[i].r)del(a[r]),r--;
while(l<q[i].l)del(a[l]),l++;
mul=1;
for(j=1;j<=scnt;j++)
if(sum[j][r]-sum[j][l-1]>0)
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]);
}