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]加起来,因为每个数可以单成一组。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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;
}