BZOJ 1025 [SCOI2009]游戏

之前找LLJ大佬推荐水题的时候让我做这个,然后不出意料的我不会。

日常抄题解。

手玩几组数据发现它N个数可以分成多个组,每个组为一个循环,他们的LCM就是最后的层数。

预处理出n以内的所有质数,我们可以把n分解成p1^a1+p2^a2+p3^a3...不同的p之间的lcm数可以直接相乘,我们用dp递推地算答案,dp[i][j表示前i个质数和为j的lcm数,然后就可以DP了。

最后统计答案要把0~n的dp[p[0]][i]加起来,因为每个数可以单成一组。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
typedef long long LL;
using namespace std;
const int maxn=1000+299;
LL n,p[maxn],bo[maxn],dp[maxn][maxn];
int main()
{
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    scanf("%lld",&n);
    for(int i=2;i<=n;i++) {
        if(!bo[i]) p[++p[0]]=i;
        for(int j=1;j<=p[0]&&p[j]*i<=n;j++) {
            bo[i*p[j]]=1;
            if(i%p[j]==0) break;
        }
     }
     dp[0][0]=1;
     for(int i=1;i<=p[0];i++){
         for(int j=0;j<=n;j++) {
             dp[i][j]+=dp[i-1][j];
             for(int k=p[i];k<=j;k*=p[i]) {
                 {
                     dp[i][j]+=dp[i-1][j-k];
                 }
             }
          }
    }
    LL ans=0;
    for(int i=0;i<=n;i++)
        ans+=dp[p[0]][i];
    printf("%lld\n",ans);
    return 0;
}
View Code

 

posted @ 2017-09-18 22:20  啊宸  阅读(86)  评论(0编辑  收藏  举报