考慮 dp,記 \(dp_{i,j}\) 表示確定前 \(i\) 個數最後一個數為 \(j\) 的方案數,則:
\[dp_{1,i}=[x_1\mid i]\\
dp_{i,j}=[x_{i-1}\mid j]\sum_{k=1}^m dp_{i-1,k}[\gcd(k,j)=x_{i-1}][x_{i-1}\mid k]\\
dp_{i,j}=[x_{i-1}\mid j]\sum_{k=1}^m\sum_{d\mid (j/x_{i-1}),d\mid (k/x_{i-1})}\mu(d)\cdot dp_{i-1,k}
\]
\[\mathbf{Answer}=\sum_{x_{n-1}|i}dp_{n,i}
\]
套個莫比烏斯反演:
\[dp_{i,j\cdot x_{i-1}}=\sum_{d|j}\mu(d)\sum_{k=1}^{m/x_{i-1}/d}dp_{i-1,kd\cdot x_{i-1}}\\
\]
發現 \(x_i\) 互不相同,於是 \(\sum \frac m {x_i}\) 是可以接受的,先對 \( \sum_k\) 的部分做一遍狄利克雷字尾和,再對 \(\sum_d\) 的部分做一遍狄利克雷字首和即可,時間複雜度 \(\mathcal O(m\log m\log\log m)\)。
參考程式碼:
#include<bits/stdc++.h>
#define ll long long
#define mxn 1000003
#define md 998244353
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rept(i,a,b) for(int i=(a);i<(b);++i)
#define drep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
int n,m,t,ans,f[mxn],s[mxn],a[mxn],d[mxn],p[mxn>>1],mu[mxn];
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
inline void add(int &x,int y){
x+=y;if(x>=md)x-=md;
}
signed main(){
n=read(),m=read();
mu[1]=1;
rep(i,2,m){
if(!d[i])d[i]=p[++t]=i,mu[i]=md-1;
rep(j,1,t){
if(p[j]>d[i]||p[j]>m/i)break;
d[p[j]*i]=p[j];
if(i%p[j])mu[p[j]*i]=md-mu[i];
}
}
rept(i,1,n)a[i]=read();
for(int i=a[1];i<=m;i+=a[1])f[i]=1;
a[0]=a[1];
rept(i,1,n){
int c=m/a[i];
rep(j,1,c)s[j]=f[j*a[i]];
rep(j,1,t){
if(p[j]>c)break;
drep(k,c/p[j],1)add(s[k],s[k*p[j]]);
}
rep(j,1,c)s[j]=(ll)s[j]*mu[j]%md;
for(int j=a[i-1];j<=m;j+=a[i-1])f[j]=0;
rep(j,1,c)f[j*a[i]]=s[j];
rep(j,1,t){
if(p[j]>c)break;
for(int k=1,k1=p[j];k1<=c;++k,k1+=p[j])add(f[k1*a[i]],f[k*a[i]]);
}
}
for(int i=a[n-1];i<=m;i+=a[n-1])add(ans,f[i]);
cout<<ans;
return 0;
}