【置换+DP】BZOJ1025

来源:互联网 发布:学java可以找什么工作 编辑:程序博客网 时间:2024/05/24 06:48

题目链接

这道题题目很长,废话太多。
说白了就是有若干个正整数,它们的和为n,求lcm即最小公倍数有多少种。

把题目看透后,似乎题变简单了。然后一眼就看出是一个DP。

然而蒟蒻还是不会做。动规弱爆了= =

决定最小公倍数的,是这些数的质因数以及对应的幂。
那么首先筛一下素数吧,然后DP。

/**************************************************************    Problem: 1025    Time:20 ms    Memory:9168 kb****************************************************************/#include <iostream>#include <cstdio>#define MAXN 1005#define LL long long intusing namespace std;bool flag[MAXN];int n, prime[MAXN], cnt;LL f[MAXN][MAXN];void table(int n){    for(int i=2;i<=n;++i)    {        if(!flag[i])prime[++cnt]=i;        for(int j=1;j<=cnt;++j)        {            if(i*prime[j]>n)break;            flag[i*prime[j]]=1;            if(i%prime[j]==0)break;        }    }}int main(){    scanf("%d",&n);    table(n);    f[0][0]=1;    //f[i][j]表示前i个素数的和为j时最小公倍数的个数(当然有一些数木有用)。由于是枚举素数,不存在最小公倍数重复的情况    for(int i=1;i<=cnt;++i)    {        for(int j=0;j<=n;++j)            f[i][j]=f[i-1][j];        for(int k=prime[i];k<=n;k*=prime[i])            for(int j=0;j+prime[i]<=n;++j)                f[i][j+k]+=f[i-1][j];    }    LL ans=0;    //注意:若和没有到达n,就用1来补。    for(int i=0;i<=n;++i)        ans+=f[cnt][i];    printf("%lld\n",ans);    return 0;}
0 0
原创粉丝点击