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