牛客网 - 猜数问题

来源:牛客网 - 2017年校招全国统一模拟笔试(秋招三模)

牛牛和羊羊在玩一个有趣的猜数游戏。在这个游戏中,牛牛玩家选择一个正整数,羊羊根据已给的提示猜这个数字。第i个提示是"Y"或者"N",表示牛牛选择的数是否是i的倍数。
例如,如果提示是"YYNYY",它表示这个数使1,2,4,5的倍数,但不是3的倍数。
注意到一些提示会出现错误。例如: 提示"NYYY"是错误的,因为所有的整数都是1的倍数,所以起始元素肯定不会是"N"。此外,例如"YNNY"的提示也是错误的,因为结果不可能是4的倍数但不是2的倍数。
现在给出一个整数n,表示已给的提示的长度。请计算出长度为n的合法的提示的个数。
例如 n = 5:
合法的提示有:
YNNNN YNNNY YNYNN YNYNY YYNNN YYNNY
YYNYN YYNYY YYYNN YYYNY YYYYN YYYYY
所以输出12 

输入描述:
输入包括一个整数n(1 ≤ n ≤ 10^6),表示已给提示的长度。

 

输出描述:

输出一个整数,表示合法的提示个数。因为答案可能会很大,所以输出对于1000000007的模

 

示例1
输入:
5

输出:
12

 


 

分析(参考 EDG_Clearlove7 和 pku_coder

从三种情况分析:

1. 如果第 i 个数为素数,那么长度为  i 的提示的个数为 dp[i] = dp[i - 1] * 2; 因为素数和之前的所有数没有关系,又第 i 个数有 Y 和 N 两种可能性;

2. 如果第 i 个数既不是素数,也不是素数的幂次,如 6 = 2 * 3,会发现 6 已经被 2 和 3 确定。例如当 2 3 为 Y Y 时,6 只能是 Y;当 2 3 为 Y N 或 N Y 或 N N,6 只能是 N。此时,长度为 i 的提示的个数为 dp[i] = dp[i - 1];

3. 如果第 i 个数为素数的幂次,它不能被唯一确定,如 4,当 2 为 Y 时,4 可能为 Y 或 N;当 2 为 N 时,4 只能为 N。那么此时 4 与 2 的集合为 24 = { NN, YN, YY },因此有 3 种可能。加入 8 后,由于 8 = 2 * 4,因此当 24 中有 N 时,8 为 N;当 24 为 YY 时,8 可能为 Y,也可能为 N。则此时有 248 = {NNN, YNN, YYN, YYY},4 种可能。加入 16 后,由于 16 = 2 * 8,因此当 28 中有 N 时,16 为 N;当 28 为 YY 时,16 可能为 Y,也可能为 N。由 8 = 2 * 4 得知,28 为 YY 当且仅当 248 为 YYY 时,因此此时有 24816 = {NNNN, YNNN, YYNN, YYYN, YYYY},5 种可能。

由以上分析可知,

如果第 i 个数为素数的 1 次幂或素数的 n(n > 1) 次幂,那么从素数的所有次幂到该数的可能性为 (幂次的所有数 + 1)。

如果第 i 个数不为素数的幂次,那么其取值被其因子唯一确定。

因此,对于输入为 n,1 不用考虑,从 2 开始考虑,例如 n = 10,则:

素数 2 的所有次幂的数为 2,4,8,则可能性为 3 + 1 = 4 种;

素数 3 的所有次幂的数为 3,9,则可能性为 2 + 1 = 3 种;

4 已经被考虑到;

素数 5 的所有次幂的数为 5,10,则可能性 2 + 1 = 3 种;

6 = 2 * 3 被 2 和 3 唯一确定;

素数 7 的所有次幂的数为 7,则可能性为 1 + 1 = 2 种;(此时也体现了第一种情况)

8 已经被考虑到;

9 已经被考虑到;

10 已经被考虑到;

由于素数之间相互独立,则总的可能性为 probability(2) * probability(3) * probability(5) * probability(7);

由以上我们能知道,对于输入 n,其提示的总的可能性为小于 n 的所有素数的次幂数的乘积。因此,编程思想为:

首先,确定所有小于 n 的素数;

其次,确定所有素数在 2 ~ n 内的所有次幂的个数;

最后,求出素数所有次幂的个数 + 1 的乘积;

 

#include <iostream>
using namespace std;

const long maxn = 1E6 + 1;
const long MOD = 1E9 + 7;

int prime[maxn] = { 0 };  // 存储是否为素数的次幂或因子有素数

int main()
{
    long n;
    cin >> n;
  // 输入判断
if (n < 1 || n > maxn) { return 0; } long long ans = 1; for (long i = 2; i <= n; ++i) {
    // 如果为 已计算的素数的次幂 或 因子中有已计算的素数,跳过
if (prime[i]) { continue; }
    // 如果是 当前素数的次幂 或 因子有当前素数
for (long j = i + i; j <= n; j += i) { ++prime[j]; } int power_num = 0; long prime_tmp = i;
     // 计算小于 n 的当前素数的次幂的个数
while (prime_tmp <= n) { ++power_num; prime_tmp *= i; }

    // 由于结果比较大,因此这里必须取模 ans
= ans * (power_num + 1) % MOD; } cout << ans % MOD << endl; return 0; }

 

 

posted @ 2017-07-31 21:17  Kovu  阅读(435)  评论(0编辑  收藏  举报