题目描述
笨小猴的词汇量很小,所以每次做英语选择题的时候都很头疼。但是他找到了一种方法,经试验证明,用这种方法去选择选项的时候选对的几率非常大!
这种方法的具体描述如下:假设 maxn 是单词中出现次数最多的字母的出现次数,minn 是单词中出现次数最少的字母的出现次数,如果 maxn-minn是一个质数,那么笨小猴就认为这是个 Lucky Word,这样的单词很可能就是正确的答案。
输入格式:
一个单词,其中只可能出现小写字母,并且长度小于 100。
输出格式:
共两行,第一行是一个字符串,假设输入的的单词是 Lucky Word,那么输出 Lucky Word
,否则输出 No Answer
;
第二行是一个整数,如果输入单词是 Lucky Word
,输出 maxn−minn 的值,否则输出 0。
输入输出样例:
输入 #1:
error
输出 #1:
Lucky Word 2
输入 #2:
olympic
输出 #2
No Answer 0
说明/提示
【输入输出样例 1 解释】
单词 error
中出现最多的字母 r 出现了 33 次,出现次数最少的字母出现了 1 次,3-1=2,2 是质数。
【输入输出样例 2 解释】
单词 olympic
中出现最多的字母 i 出现了 1 次,出现次数最少的字母出现了 1 次,1-1=0,0 不是质数。
(本处原题面错误已经修正)
noip2008 提高第一题
思路:
看到这道题,我们首先就是要找到一个字母出现次数最多是多少,最少出现次数是多少? 题目规定,输入最长为长度100的字符串a,我们可以用strlen(a)函数求出字符串a的长度t。
我们怎么知道出现次数最多是多少?最少是多少呢?回想我们以前,输入一串数字之后,如何知道最多次数,最少次数?当然是桶了,但是我们输入的是字符啊,这个桶的下标不可能是一个字符。
对,不可能!但是我们可以进行(int)类型的强制转换啊,我们知道,题目输入的字符串全都是小写字母,我们将输入的每一个字母进行(int)强制转换,变化为桶的下标,字母'a'的ASCII码为97,字母'z'的ASCII码为122,所以这个桶的下标应该在97~122之间,那0~96之间怎么办呢?是空的,那不有些浪费空间了吗。
这样子来说,我们知道,'a'是26位英文字母的第一个,如果要下标为1,那么我们就可以将'a'-'a'+1当作桶的下标,如果字符是'b',那么'b'-'a'+1就等于2,这样来说,我们这个桶的下标空间就为1~26之间,为了保险起见,我们将桶的空间设置为30,都初始化为0.
经过桶的计数之后,我们定义Max,Min,从桶的下标0~29之间找最大值和最小值,因为刚开始我们都初始化为0了,如果为0,那么代表输入的字符串里面没有这个编号的字符。所以,我们要判断如果不等于0的话,和Max,Min进行比较,找出最大值和最小值。
找出最大值和最小值之后,我们要判断两者相减是否是一个质数Max-Min,如果是就输出Lucky Word,然后换行输出Max-Min的值。
如果不是就输出No Answer,然后换行输出0.
那我们怎么判断一个数是不是质数呢?
我们需要写一个判断一个整数是否是一个素数的函数:
素数是什么呢?
是除了1和它本身以外没有任何的因子.
那么我们只要发现它的一个因子就可以说他不是素数,反之,返回true.
因子是什么?
一个数除以它的因子余数为0.
我们可以根据这一点来进行判断,进行for枚举.
那么范围是多少呢,1不是素数也不是合数,要在一开始进行特判.
那么初始从=2开始,小于n吗?
这样也可以,但是还可以进行优化.
拿25来说,从2枚举到25,是不是浪费了很多.
我们只要取25的根号,也就是5来当=2;<=5;
为什么呢?
因为5是他一个因子中最大的,只要看5以下的就行了.
我们来细分以下,拿24为例:
24=1*24;
24=2*12;
24=3*8;
24=4*6;
你看,我们给24开个根号,值在4~5之间,也就是说循环最多到4.
循环过程:
24%2=0;
24%3=0;
24%4=0;
你们可能会疑惑,还有12,8,6没有除余判断呢!
其实根本没有必要,2,3,4和12,8,6相乘等于24,只要2,3,4除余为0,那么代表着12,8,6和24相除余数为0.
这样,我们的基本思路就讲到这里了,接下来给大家看一下代码吧!
代码:
#include<bits/stdc++.h> //万能头文件
using namespace std; //批准使用std类
int pd(int x){ //判断一个整数是不是素数
bool f=true; //刚开始定义为是素数
int k; //循环变量
if(x==1||x==0) //1既不是素数也不是合数,要首先排除掉
f=false;
for(k=2;k<=sqrt(x);k++){ //循环遍历,sqrt函数是求一个整数开了根号后的值.
if(x%k==0){ //素数不能和1除外和他本身除外的任何数余数为0
f=false; //代表有一个因数了,就不是素数了
break; //退出
}
else
f=true; //是素数
}
return f; //返回
}
int main(){ //main主函数
char a[101]; //定义字符串
int f[30]={0},M='z'; //定义桶和最小的字母编号
cin.getline(a,101); //输入字符串
int t=strlen(a); //求出字符串的长度
for(int i=0;i<t;i++) //进行桶计数遍历
f[a[i]-'a'+1]++,M=min(M,a[i]-'a'+1); //找出最小的字母编号和统计字母出现次数
int Max=f[M],Min=f[M]; //初始定义为最小字母编号出现次数
for(int i=1;i<30;i++){ //遍历桶
if(f[i]!=0){ //只要桶不为0
if(f[i]>Max) //如果有比Max更大的
Max=f[i]; //赋值
if(f[i]<Min) //如果有比Min更小的
Min=f[i]; //赋值
}
}
if(pd(Max-Min)) //判断最大值减去最小值的差是不是质数
cout<<"Lucky Word\n"<<Max-Min<<endl; //输出
else //不是质数
cout<<"No Answer\n0"<<endl; //输出
return 0; //结束
}
总结:
这道题是2008年提高组第一题,但是难度不算很高,只有普及1~2题的难度,考的知识点也很多:质数的判断,字符桶计数,找数组最大最小值。
对于一个初学者来说,应该算是挺难的了!
题目链接:
[NOIP2008 提高组] 笨小猴 - 洛谷https://www.luogu.com.cn/problem/P1125