您的位置:首页 > 编程语言 > PHP开发

【數論】【搜索】【SCOI2009】遊戲

2012-02-09 20:31 141 查看
Description
windy学会了一种游戏。对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应。最开始windy把数字按顺序1,2,3,……,N写一排在纸上。然后再在这一排下面写上它们对应的数字。然后又在新的一排下面写上它们对应的数字。如此反复,直到序列再次变为1,2,3,……,N。 如: 1 2 3 4 5 6 对应的关系为 1->2 2->3 3->1 4->5 5->4 6->6 windy的操作如下 1 2 3 4 5 6 2 3 1 5 4 6 3 1 2 4 5 6 1 2 3 5 4 6 2 3 1 4 5 6 3 1 2 5 4 6 1 2 3 4 5 6 这时,我们就有若干排1到N的排列,上例中有7排。现在windy想知道,对于所有可能的对应关系,有多少种可能的排数。
Input
包含一个整数,N。
Output
包含一个整数,可能的排数。
Sample Input
【输入样例一】
3

【输入样例二】
10

Sample Output
【输出样例一】
3

【输出样例二】
16

【数据规模和约定】
30%的数据,满足 1 <= N <= 10 。
100%的数据,满足 1 <= N <= 1000 。
這是一道數論+記憶化搜索的題目。

遠問題可以轉化為一下問題:

已知a1+a2+a3+...+am = N,求Lcm(a1, a2, a3, ..., am)的所有可能性。

做法如下:枚舉從1到n之間的所有素數,再枚舉每個素數的方冪。由唯一分解定理可知,所枚舉的每一個不同的對象,都對應一個不同的解,再將這些解累加即可。

由於數據較大,必須使用記憶化搜索,並且要用64位整型。

Accode:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using std::cin;
using std::cout;
typedef long long int64;
const int maxN = 1010;
const int maxM = 210;

int prime[210];
int64 f[210][1010];
int n;

inline void mkprime(int Lim)
{
prime[0] = 2; prime[1] = 3; prime[2] = 5;
int Last = 7;
for (int i = 3; Last <= Lim; ++i, ++Last)
for (; ; ++Last)
{
bool flag = true;
for (int j = 0; prime[j]
* prime[j] <= Last; ++j)
if (Last % prime[j] == 0)
{
flag = false;
break;
}
if (flag)
{
prime[i] = Last;
break;
}
}
} //製作一張素數表。

int64 Find(int i, int n)
{
if (prime[i] == -1 || prime[i] > n)
//處理邊界。
return f[i]
= 1;
if (f[i]
> -1) return f[i]
;
//記憶化搜索。
f[i]
= 0;
for (int tmp = prime[i];
tmp <= n; tmp *= prime[i])
f[i]
+= Find(i + 1, n - tmp);
//該素數被選,則枚舉它的次數。
return f[i]
+= Find(i + 1, n);
//統計該素數未被選的情況。
}

int main()
{
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
cin >> n;
memset(f, 0xff, sizeof(f));
memset(prime, 0xff, sizeof(prime));
mkprime(n);
cout << Find(0, n);
return 0;
}

第二次做,改进递推版,并且加上就地滚动,速度更快。

#include <fstream>
#include <cstring>
#include <cstdlib>

typedef long long int64;
const int maxP = 200;
const int maxN = 1010;

int64 f[maxN];
int prime[maxP];
int n, tot;

bool is_prime(int x)
{
for (int i = 0; prime[i]
* prime[i] <= x; ++i)
if (x % prime[i] == 0)
return false;
return true;
}

void mkprime()
{
prime[0] = 2;
for (int i = 3; i < n + 1; ++i)
if (is_prime(i))
prime[++tot] = i;
return;
}

int main()
{
std::ifstream cin("game.in");
cin >> n;
cin.close();
mkprime();
for (int j = 0; j < n + 1; ++j)
f[j] = 1;
for (int i = 0; i < tot + 1; ++i)
for (int j = n; j > -1; --j)
for (int k = prime[i];
k <= j; k *= prime[i])
f[j] += f[j - k];
std::ofstream cout("game.out");
cout << f
<< std::endl;
cout.close();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  output input 游戏