您的位置:首页 > 大数据 > 人工智能

2012 Multi-University Training Contest 5 Problem F Permutation(HDU4345)

2015-08-20 18:24 465 查看
http://acm.hdu.edu.cn/showproblem.php?pid=4345

分析:

题目描述:
有N个元素的一个集合经过K次置换能变回原来的集合,求k的个数。
解题思路:
k为置换群中各独立置换群长度的最小公倍数,
k的个数即N以内的总和小于10的质数的乘积(包括1)
比如N=10时,k可为:1,2,3,2*2,5,2*3,7,2*2*2,3*3,2*5,2*2*3,2*7,3*5,2*2*5,3*7,2*3*5,共16个

解法:DP
状态:
dp[i][j]表示当前和为i,且包含最大质因子不超过素数表第j个素数的情况。
状态转移时
dp[i][x] = dp[i-x][t-1]+dp[i-x^2][t-1]+....dp[i-x^k][t-1]
用到唯一分解定理,以质因子去构造状态,
但是状态转移的时候,只考虑质因子的幂,
不考虑两个质因子的不同幂所组成的和,比如6(2+4),12=(3+9),
这种情况是因为当你有i^p时,再多加一个质因子i^p1(p1<p),
结果不变,可以用i^p1个1来代替。
那么如何处理1的问题,算最后结果的时候把dp[1][m]+...+dp
[m],
算和就是了。因为dp的时候,没有考虑1,不用担心重复问题。


#include <iostream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <bitset>
#include <string>
#include <numeric>
#include <algorithm>
#include <functional>
#include <iterator>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <complex>
#include <ctime>

typedef long long LL;
const double pi = acos(-1.0);
const long long mod = 1e9 + 7;
using namespace std;

LL dp[1005][1005],sum[1005];
int prime[1005],a[1005];

void isprime(int &m)//找出1000内所有的质数并存在a数组里
{
for(int i = 2;i < 1005;i++)
{
if(prime[i] == 0)
{
a[++m] = i;
for(int j = 2 * i;j < 1005;j += i)
prime[j] = 1;
}
}
}

int main()
{
//freopen("int.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m = 0;
memset(prime,0,sizeof(prime));
isprime(m);
dp[0][0] = 1;
for(int j = 1;j <= m;j++)
{
dp[0][j] = dp[0][j - 1];
for(int i = 2;i < 1005;i++)
{
int x = a[j];
dp[i][j] += dp[i][j - 1];
while(i >= x)
{
dp[i][j] += dp[i - x][j - 1];
x *= a[j];
}
}
}
sum[1] = 1;
for(int i = 2;i < 1005;i++)
sum[i] = sum[i - 1] + dp[i][m];
while(scanf("%d",&n) != EOF)
{
printf("%I64d\n",sum
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: