想都没想到的动态规划:猜数字游戏

牛牛和羊羊在玩一个有趣的猜数游戏。在这个游戏中,牛牛玩家选择一个正整数,羊羊根据已给的提示猜这个数字。第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

解题思路:

首先我必须承认这个题把我按在地上摩擦了一回,看到题目首先我想到了使用回溯算法,但由于是4的倍数一定是2的倍数,是2的倍数不一定是4的倍数,只是这两者之间的关系,就让我的这个萌芽枯萎了,自认为控制不了。

正如上面所说的两个位置之间存在有依赖关系,所以开始没往动态规划方面思考(看来还是太嫩了,不熟练算法)。

不过还好,看到大神的代码,了解使用动态规划,自己也理解了。

其实,自我认为解法不算是动态规划,更像是智力题,找规律。

下面我们进入正题:

我们只需要那n=6时为例就可以

因为正数都是1的倍数所以,第一个位置一定是Y。

素数2,3,5没有任何限制可以是Y也可以是N。

而像4是2的倍数,所以2为Y的时候,4既可以为Y也可以为N。但是若2为N的时候,4也必须为N。否则不合法。

还有一类:6,既不是素数,也不是素数的幂次方数,但是他有2和3限制:

2为Y,3为Y    :6为Y

2为N,3为N   :6为N

2为Y,3为N:   6为N

2为N,3为Y:  6为N

所以像6这类数:有其他两个数控制也能为Y或者N。


由上面的图:我们可以观察到对应位置的解的个数,为幂数+1.(由于他们是“一根绳上的蚂蚱”,所以是最高次幂+1)

所以我们可以分为几种情况

1位置:1种情况即Y

素数及其幂次方数:最高次幂+1种情况

非素数也不是素数的幂次方:1种情况

代码实现:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int mod=1000000007;
//判断一个数是否为素数
bool  Primenum(int num)
{
    if (num<2)
		return false;
	for (int i = 2; i <= sqrt(num); ++i)
	{
		if (num%i == 0 && num != 2)
			return false;
	}
	return true;
}

//本体的主体函数
int Guessnum(int n)
{
    if(n<=0)
        return 0;
    if(n==1)
        return 1;
    vector<int> arr(n+1,1);//用一个数组存放求取的结果,存放结果  最高次幂+1
    long long ret=1;
    for(int i=2;i<=n;++i)
    {   //当一个数为素数时,找范围内的最高次幂
          int j=1;
        if(Primenum(i))
        {   
            long long num=i;
            while(num<=n)
            {
                
                num=num*i;
                j++;
            }
            arr[num/i]=j;
        }
    }
//遍历数组求取结果
    for(int i=1;i<=n;++i)
    {
        ret=ret*arr[i]%mod;
    }
    return (int)ret;
}





int main()
{
    int n;
    cin>>n;
    cout<<Guessnum(n)<<endl;;
    return 0;
}

我们可以节约空间,不适用vector存放

int Guessnum(int n)
{
    if(n<=0)
        return 0;
    if(n==1)
        return 1;
    long long ret=1;
    for(int i=2;i<=n;++i)
    {    int j=1;
        if(Primenum(i))
        {   
            long long num=i;
            while(num<=n)
            {
                
                num=num*i;
                j++;
            }
            ret=ret*j%mod;
        }
    }

    return (int)ret;
}

你们的 【三连】 是给Qyuan最大的肯定!

↓          ↓           ↓

注:如果本篇博客有任何错误和建议,欢迎伙伴们留言,你快说句话啊!

 

链接:https://www.nowcoder.com/questionTerminal/0a5b316cfe9d4c4ba89c6c57a1ee516e 

如果需要练习的小伙伴,可以打开上方链接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值