Math Magic ZOJ - 3662

核心是要想到只枚举最小公倍数的因子

因为转移过程中一单添加了不是最小公倍数的因子,那么结果必然不合法,虽然最终答案是对的,但是这样的答案根本用不上,反而时间复杂度大大增加

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
#define endl "\n"
#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;
    }
}

 

posted on 2019-03-05 17:23  欣崽  阅读(265)  评论(0)    收藏  举报

导航