核心是要想到只枚举最小公倍数的因子
因为转移过程中一单添加了不是最小公倍数的因子,那么结果必然不合法,虽然最终答案是对的,但是这样的答案根本用不上,反而时间复杂度大大增加
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<iostream> using namespace std; #define endl " " #define me(a,b) memset(a,b,sizeof(a)) const int mod=1e9+7; const int inf=0x3f3f3f3f; const int maxn=1005; int lcm[maxn][maxn]; void prepear() { for(int i=1; i<=1000; i++) for(int j=1; j<=1000; j++) lcm[i][j]=(i*j)/__gcd(i,j); } int n,m,k; int dp[2][maxn][maxn]; int factor[105],tol; int main() { prepear(); while(cin>>n>>m>>k) { tol=0; for(int i=1; i<=m; i++) if(m%i==0) factor[tol++]=i; me(dp,0); dp[0][0][1]=1; int dir=0; for(int i=1; i<=k; i++) { dir^=1; me(dp[dir],0); for(int j=i-1; j<=n; j++) { for(int l=1; l<=m; l++) { if(dp[dir^1][j][l]!=0) { for(int eu=0;eu<tol;eu++){ int v=factor[eu]; if(v+j>n) break; int nlcm=lcm[l][v]; if(nlcm>m||m%nlcm) continue; (dp[dir][v+j][nlcm]+=dp[dir^1][j][l])%=mod; } } } } } cout<<dp[dir][n][m]<<endl; } }