题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3662
刚开始以为是个搜索题,拿着搜了+剪枝果断超时了,
后来很容易想到DP,DP很容易推,但是这个题关键恶心的地方就在于卡时间(平时也就算了,放到现场赛有意思吗??)。
这题我是勉强A的(2.4S+),要预处理出来LCM[1000][1000],而且用memset清零超时还A不掉,用for循环选择清零才A。。搞了我一个多小时,太无聊了。。。
CODE:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int mod = 1000000007;
int lcm[1011][1011];
int dp[2][1011][1011];//k,n,m
int num[1011];
int n,m,k;
int gcd(int a,int b)
{
if(a<b)swap(a,b);
int r = b;
while(r)
{
r = a%b;
a = b;
b = r;
}
return a;
}
int Lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
int main()
{
//freopen("input.txt","r",stdin);
for(int i=1;i<1001;i++)
for(int j=1;j<1001;j++)
lcm[i][j] = Lcm(i,j);
while(~scanf("%d%d%d",&n,&m,&k))
{
int cnt = 0;
for(int i=1;i<=m;i++)
if(m%i==0)num[cnt++] = i;
for(int t=0;t<=n;t++)
for(int j=0;j<cnt;j++)
dp[0][t][num[j]]=0;
dp[0][0][1] = 1;
for(int i=1;i<=k;i++)
{
int pre = (i-1)&1,now = i&1;
for(int t=0;t<=n;t++)
for(int j=0;j<cnt;j++)
dp[now][t][num[j]]=0;
for(int t=i-1;t<=n;t++)
for(int j=0;j<cnt;j++)
{
if(dp[pre][t][num[j]] == 0)continue;
for(int p = 0;p<cnt;p++)
{
int x = t + num[p];
int y = lcm[num[j]][num[p]];
if(x>n || m%y!=0)break;
dp[now][x][y] += dp[pre][t][num[j]];
dp[now][x][y] %= mod;
}
}
}
printf("%d\n",dp[k&1][n][m]);
}
return 0;
}