核心思路
维护因数位置
使用了一种dp技巧,对特例改为范围。
记f(i,j) 表示a[i]被拆分成若干个(数量不限)<= a[j] 的因子的方案数。
则拓宽边界采用f[i][j] += f[pos][j-1];//本质上就是加上了a[j]*a[pos] 的方案 (单对多)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e6+7;
long long f[7050][7050];//f[i][j]表示将ai拆成若干个小于aj的数的方案数
int pos[3][2*N];
int a[N];
int tot;
int mod = 998244353;
signed main(){
int t;
cin>>t;
while(t--){
memset(f,0,sizeof(f));
memset(pos,0,sizeof(pos));
int n;
cin>>n;
tot = 0;
for(int i = 1;i*i <= n;i++){
if(n%i == 0){
a[++tot] = i;
if(n/i != i)a[++tot] = n/i;
}
}
sort(a+1,a+1+tot);
for(int i = 1; (i << 1) <= tot + 1; i++) //记录pos
{
pos[1][a[i]] = i;
pos[2][a[i]] = tot - i + 1;
//排序对称性
}
for(int i = 1;i <= tot;i++){
if(i == 1) f[i][1] = 1; //初始化
for(int j = 2;j <= tot;j++){
f[i][j] = f[i][j-1];//不使用aj的情况
if(i < j)continue;
if(a[i]%a[j] == 0){
int tmp = a[i]/a[j];
int p ;
if(tmp<=(long long)sqrt(n))p = pos[1][tmp];
else p = pos[2][n/tmp];
f[i][j] = (f[i][j] + f[p][j-1]) % mod;
}
}
}
cout<<f[tot][tot]-1<<endl;
}
return 0;
}