题目描述
Guyu Guo和Tube Lu正在玩一个游戏:Lu默想一个1和n 之间的数x,然后Guo尝试猜出这个数。
Guo能提出m个这样的问题: “未知数是否能被yi整除?”
游戏按照如下流程进行:Guo先给出他想问的全部m个问题,然后Lu对所有问题依次以“是”或“否”作答。得到m个问题的答案之后,Guo就要给出他的猜测。
Guo写了一个程序帮他以最优的方式提出这m个问题,现在他想知道在保证得到一个确定的答案下,最少可以问多少个问题,即m的最小值。
输入
一行,一个整数n
输出
一行,一个整数m(表示最少问m个问题)
样例输入
【样例输入1】
4
【样例输入2】
8
样例输出
【样例输出1】
3
【样例输出2】
6
样例1解释:
Guo依次提问能否被2,3,4整除,就可以得到确定答案。
比如Lu回答能被2,4整除,不能被3整除,则确定答案为4
样例2解释:
Guo依次提问能否被2,3,4,5,7,8整除,总共需要6次。
分析
其实这题我一开始看到完全是懵逼的,样例都看不懂。
经过ymw大佬的指点,我恍然大悟。。。
我们可以发现一个规律:要问的数就是小于等于n的k^p。k是质数,p是正整数。
ymw大佬还指出:这种题一般都是猜结论然后证明,可以手推几个小样例。
至于这个规律怎么证明,我也没太懂,放几张截图大伙看看:
这时我写了一篇代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int a[100001]={0},s[100001]={0};
long long ans,sum;
int pdzs(int x)
{
int p=0;
for(register int k=2;k<=x-1;k++)
{
if(x%k==0)
{
return 0;
}
}
return 1;
}
int main()
{
// freopen("game.in","r",stdin);
// freopen("game.out","w",stdout);
cin>>n;
for(register int i=2;i<=n;i++)
{
if(pdzs(i)==0) continue;
else
{
for(register int j=1;j<=n;j++)
{
sum=pow(double(i),double(j));
if(sum<=n&&a[sum]==0)
{
ans++;
a[sum]=1;
}
else break;
}
}
}
cout<<ans;
fclose(stdin);
fclose(stdout);
return 0;
}
结果超时了。。。。。
dalao介绍了埃式筛法。就是筛去所有质数的倍数。我做了一个变式:筛去质数的倍数,留下质数的次幂,最后没被筛去的就是答案数量,累加即可。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int ip[100001];
long long t;
int main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
int n;
cin>>n;
for(int i=2;i<=n;i++)
{
ip[i]=1;
}
for(long long i=2;i<=n;i++)
{
if(ip[i]==1)
{
for(int j=2*i;j<=n;j+=i)
{
ip[j]=0;
}
for(long long k=i*i;k<=n;k*=i)
{
ip[k]=2;
}
}
}
// for(int i=1;i<=n;i++)
// {
// cout<<ip[i]<<' ';
// }
for(int i=2;i<=n;i++)
{
if(ip[i]==1||ip[i]==2) t++;
}
cout<<t;
fclose(stdin);
fclose(stdout);
return 0;
}