洛谷3861八月月赛A题解
用f[i][j]表示乘积为i的,包含的最大数小于等于j时的方案总数
我们先考虑所用的数为1到n的情况
最后的答案就是f[n][n]-1
转移时考虑f[i][j]可以转移到的状态
显然f[i][j]可以转移到f[i*k][k](k>j),可以转移到f[i][k](k>j)
我们在考虑,可以发现只有i,j都为n的因数时才会对答案产生贡献
而1e12中因数最多的数有大约7000个因数,所以我们就可以愉快的O(7000^2)水过去了
# include<iostream> # include<cstdio> # include<cstring> # include<cmath> # include<algorithm> using namespace std; typedef long long LL; const int mod = 998244353; const int mn = 8005; LL f[mn][mn],a[mn],n; int cnt,t; void work(LL x) { LL m=sqrt(x*1.0); for(int i=1;i<=m;i++) { if(x%i==0) { if(1ll*i*i==x) a[++cnt]=i; else { a[++cnt]=i; a[++cnt]=x/i; } } } sort(a+1,a+1+cnt); a[cnt+1]=x+5;//增加虚拟节点 f[1][1]=1; //printf("%d",cnt); for(int i=1;i<=cnt;i++) { int l=i+1; for(int j=1;j<cnt;j++) { if(f[i][j]==0) continue; if(a[i]*a[j+1]<=x) { while(a[l+1]<=a[i]*a[j+1]) l++; if(a[l]==a[i]*a[j+1]) f[l][j+1]=(f[l][j+1]+f[i][j])%mod; } f[i][j+1]=(f[i][j+1]+f[i][j])%mod; } } } int main() { scanf("%d",&t); while(t--) { cnt=0; //memset(f,0,sizeof(f)); scanf("%lld",&n); work(n); printf("%lld\n",f[cnt][cnt]-1); if(t) { for(int i=1;i<=cnt;i++) for(int j=1;j<=cnt;j++) f[i][j]=0; } } return 0; }