http://acm.hdu.edu.cn/showproblem.php?pid=4345
题意(有点纠结):
给你一个数N(1<=N<=1000),求这么N有多少个不同的旋转长度。旋转长度是指,一个数最少经过多少步可以回到原来的数。例如N=6时,假如123、45、6分别为三个旋转周期,则旋转顺序为:123456,312546, 231456, 123546, 312456, 231546,123456,旋转长度为6。当然你也可以12,34,56旋转周期,旋转长度为2。
思路:
想想后会发现可转换为求相加和小于N的正整数的最小公倍数的可能数。如果这些正整数包含大于一个质因子,只会使得正整数的和更大。因而问题再次转化为相加小于等于N的若干质数的k次幂的最小公倍数的可能数。因为质数的i次幂与其他质数的j次幂依然互质,所以最小公倍数乘起来就行了。
#include<stdio.h>
#include<string.h>
#include<math.h>
bool is[1101];
int prm[1101];
__int64 n,i,j,dp[1001][1001];
int getprm(int n)
{
int i, j, k = 0;
int s, e = (int)(sqrt(0.0 + n) + 1);
memset(is, 1, sizeof(is));
prm[k++] = 2; is[0] = is[1] = 0;
for (i = 4; i < n; i += 2) is[i] = 0;
for (i = 3; i < e; i += 2) if (is[i])
{
prm[k++] = i;
for (s = i * 2, j = i * i; j < n; j += s)
is[j] = 0;
}
for ( ; i < n; i += 2) if (is[i]) prm[k++] = i;
return k;
}
void dfs(__int64 n,__int64 x)//和小于n,从第x个素数开始有多少种情况
{
__int64 i,j,t=1;
if(dp[n][x]) return;
if(n<prm[x]){dp[n][x]=1;return;}//边界条件,如果当前质数比当前的n还大,就返回
if(!dp[n][x+1]) dfs(n,x+1);
dp[n][x]=dp[n][x+1];//不取当前的素数
for(i=0;;i++)
{
t*=prm[x];
if(n-t<0) break;
if(!dp[n-t][x+1]) dfs(n-t,x+1);
dp[n][x]+=dp[n-t][x+1];//取当前的素数i次幂
}
}
int main()
{
getprm(1101);//筛素数,一定要筛到大于1000的一个素数
memset(dp,0,sizeof(dp));
while(~scanf("%I64d",&n))
{
dfs(n,0);
printf("%I64d\n",dp[n][0]);
}
}