您的位置:首页 > 其它

ZOJ Problem Set - 3662 Math Magic

2012-10-18 23:23 316 查看
The 2012 ACM-ICPC Asia Changchun Regional Contest-H

题目大意就是给出n,m,k求有多少种方案k个数的和为n,lcm为m。

数据范围DP勉强能接受f[k][i][j]表示已经找出k个数,和为i,lcm为j的方案数。用滚动数组优化内存。

然后因为多组数据还需优化一下,要最后lcm是m,则j一定是m的约束,所以枚举j时枚举m的约束即可。

预处理两个数之间的lcm。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MOD 1000000007
using namespace std;
int f[2][1005][1005],lcm[1005][1005],temp[1005];

int gcd(int a,int b){
int r=0;
while (b>0) r=a%b,a=b,b=r;
return a;
}
int cnt,tot,n,m,k;
int LCM(int a,int b){ return (a*b/gcd(a,b));}
int main()
{
for (int i=1;i<=1000;++i)
for (int j=i;j<=1000;++j)
lcm[i][j]=lcm[j][i]=LCM(i,j);

while (scanf("%d%d%d",&n,&m,&k)!=EOF){
cnt=tot=0;
for (int i=1;i<=m;++i)
if (m%i==0) temp[tot++]=i;
for (int i=0;i<=n;++i)
for (int j=0;j<tot;++j) f[cnt][i][temp[j]]=0;

for (int i=0;i<tot;++i) f[cnt][temp[i]][temp[i]]=1;
for (int t=2;t<=k;++t)
{
for (int i=0;i<=n;++i)
for (int j=0;j<tot;++j) f[1-cnt][i][temp[j]]=0;
for (int i=0;i<=n;++i)
for (int j=0;j<tot;++j)
if (f[cnt][i][temp[j]])
for (int l=0;l<tot;++l)
if (i+temp[l]<=n && lcm[temp[j]][temp[l]]<=m){
f[1-cnt][i+temp[l]][lcm[temp[j]][temp[l]]]+=f[cnt][i][temp[j]];
if (f[1-cnt][i+temp[l]][lcm[temp[j]][temp[l]]]>=MOD)
f[1-cnt][i+temp[l]][lcm[temp[j]][temp[l]]]-=MOD;
}
cnt=1-cnt;
}
cout<<f[cnt]
[m]<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: