您的位置:首页 > 其它

HDOJ 4345 Permutation(分组背包 + 数论)

2012-11-04 15:07 471 查看
题意:

给你一个数N(1<=N<=1000),求这么N有多少个不同的旋转长度。旋转长度是指,一个数最少经过多少步可以回到原来的数。

例如 N = 6 时,假如123、45、6分别为三个旋转周期,则旋转顺序为:123456,312546, 231456, 123546, 312456, 231546,123456,旋转长度为6。

当然你也可以12,34,56旋转周期,旋转长度为2。

思路:

即将一个数分成若干份,这若干份不同的最小公倍数的总和,5+4 即5+2^2,最小公倍数为20是一种选择方案

第一组为:2, 2^2, 2^3, ......

第二组为:3, 3^2, 3^3, ......

以此类推,每一组最多只能选择一种解决方案

dp
为填充容量不大于n时,解决发难的总和,若最终选择结果不等于n,则相当于填充了1

其实还可以理解成第0组:1, 11, 111......

对于初始化就有,用第0组物品填充,于是dp[0] ~dp
= 1

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;

const int MAXN = 1001;
__int64 dp[1005];
vector<int> v[200];

bool isprime(int n)
{
for (int j = 2; j <= sqrt(n*1.0); ++j)
if (n % j == 0)
return false;
return true;
}

int main()
{
int c = 0;
for (int i = 2; i < MAXN; ++i)
{
if (isprime(i))
{
v[c].clear();
for (int j = i; j < MAXN; j *= i)
v[c].push_back(j);
++c;
}
}
int n;
while (scanf("%d", &n) != EOF)
{
for (int i = 0; i <= n; ++i)
dp[i] = 1;
for (int i = 0; i < c; ++i)
for (int j = n; j >= 1; --j)
for (int k = 0; k < v[i].size() && v[i][k] <= j; ++k)
dp[j] += dp[j-v[i][k]];
printf("%I64d\n", dp
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: