2015AHOI小学-T1- 糖果甜度 [candy]
题目描述
卡卡西是一个奇幻小说迷,一直憧憬着自己有一天能变成超人,为正义而战。有一天,她放学回家,路过熟悉的糖果店,发现糖果店店员闷闷不乐的样子,正义的卡卡西赶紧上前询问,了解原因。原来贪婪的店长近期为了节省开支,减少店员,想出题进行员工考核,到期答不出考题的店员就要被解聘。考题是这样的:在一堆甜度不同的 n 个糖果中,假设只能吃 k 个糖果,请问能吃到的最大甜度之和是多少。卡卡西冲着店员自信的一笑,拍拍胸脯说:“放心吧,我来帮你解出这道题,你一定不会被解聘的!”聪明的小朋友们,你们知道如何解出这道题,帮助店员度过难关吗?
输入格式
输入数据有两行:
第一行有两个数,分别表示糖果的总个数 n 和能吃的糖果个数 k。
第二行有 n个数,用空格分开,分别表示每个糖果的甜度。
输出格式
能吃到的最大甜度之和。
输入输出样例
输入样例1:
5 2 6 2 5 1 8
输出样例1:
14
说明
样例解释:先吃甜度为 8 的糖,再吃甜度为 6 的糖,甜度之和为 14。
数据范围:0<n≤10000,0≤k≤1000,0<每个糖果的甜度≤100。
【耗时限制】1000ms 【内存限制】128MB
解析
考点:贪心
贪心策略:优先选择甜度大的糖果
参考代码
#include<bits/stdc++.h>
using namespace std;
int a[10000];
bool cmp(int a,int b){
return a>b;
}
int main(){
int n;
cin>>n;
int k;
cin>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1,cmp);
int s=0;
for(int i=1;i<=k;i++){
s=s+a[i];
}
cout<<s;
}
2015AHOI小学-T2- 手机密码 [phone]
题目描述
卡卡西帮糖果店店员解决了难题,店员叔叔从包里小心翼翼的拿出一个特殊的手机,说到:“为了表示对你的感谢,我要赠送给你一个神奇的手机,这个手机是我小时候超人送给我的,在关键时刻使用这个手机,就能见到超人,帮助你实现一个愿望。”这个手机的键盘是这样的:
要想按出英文字母,就必须要按数字键多次。例如要按出 x,就得按 9 两次,第一次会出现 w,而第二次会把 w 变成 x。0 键按一下会出现一个空格。
“但是,这个手机的密码需要解决以下问题才可以破解,可惜我一直都破解不了,你这么聪明,一定能够将难题迎刃而解……”此时,卡卡西的眼里已充满了惊喜,她下定决心,一定要破解手机密码,见到超人,实现愿望!问题是这样的:如果要在手机上输出只包含英文小写字母和空格的句子,则至少需要按多少次键盘。小朋友们,赶紧帮卡卡西想想办法,将密码破解吧!
输入格式
输入数据共一行,是一个句子,只包含英文小写字母和空格,且不超过200 个字符。(英文各单词之间只有一个空格,句子末尾无空格)
输出格式
一个正整数,表示至少按键盘的次数。
输入输出样例
输入样例1:
a kvz
输出样例1:
11
【耗时限制】1000ms 【内存限制】128MB
解析
考点:字符串,字符映射对应整数
思路:
1.预处理打表,将每个字母需要按的次数存储起来,a[26]。
2.遍历字符串s,将字符串中的每个字符映射成a数组中的0~25的下标即可。
参考代码
#include<iostream>
#include<string>
using namespace std;
//打表预处理
int a[26]={1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,1,2,3,1,2,3,4};
int main(){
int sum=0;
string s;
getline(cin,s);
for(int i=0;i<s.size();i++){
if(s[i]!=' '){
//将字符映射为整数 s[i]-'a'
sum+=a[s[i]-'a'];
}else{
sum++;
}
}
cout<<sum;
return 0;
}
2015AHOI小学-T3- 整数之和 [datasum]
题目描述
密码问题迎刃而解,即刻响起一串轻快的开机音乐,哈哈,手机终于可以使用了!忽然,一个神秘的手机精灵从屏幕上出现了,她笑嘻嘻的问卡卡西:“卡卡西,你是不是想见超人啊?”卡卡西迫不及待的点点头,手机精灵说:“那你需要再回答我一个问题。请你随便报出一个正整数 n,我会即刻在手机屏幕上生成一串由递增的不同的正整数所组成的序列,你需要在 5 分钟内回答出,此序列中有多少个数,恰好等于另外两个数之和。”卡卡西朝着手机精灵自信的一笑,不到一分钟就报出了答案,手机精灵按照之前的承诺,对着手机念了念咒语, “轰”的一声,天空中突然出现一道金光,超人出现啦!卡卡西实在按捺不住心中的喜悦,对着超人大声喊:“超人,超人,我是卡卡西,我要怎样才能拥有你的超能力呢?”,超人轻轻的抚摸着卡卡西的头,笑呵呵的说:“哈哈,卡卡西,你学习努力,又维护正义,你已经是个超人啦……”,说完一个跃起,消失在空中。卡卡西在心中默念:放心吧,超人,我一定会再接再厉,将正义坚持到底……
小朋友们,你们知道卡卡西是如何求解的吗?
输入格式
输入数据共两行。第一行的一个数是指不同正整数的个数 n,第二行为空格分割的 n 个正整数。
输出格式
一个正整数。表示在 n 个数中恰好等于另外两个数之和的正整数的数目。
输入输出样例
输入样例1:
4 1 3 4 7
输出样例1:
2
输入样例2:
6 1 2 3 4 5 7
输出样例2:
4
说明
样例 1 解释:因为 4=1+3;7=3+4,所以输出为 2。
样例 2 解释:因为 3=1+2;4=1+3;5=1+4=2+3;7=2+5=3+4,所以输出为 4。
数据范围: 0<n≤1000,0<n 个数中每个数≤1000
【耗时限制】1000ms 【内存限制】128MB
解析
考点:枚举+数组标记
朴素做法:三层循环,前两层分别枚举两个加数,最内层循环验证枚举的加数和是否在数组中出现过,时间复杂度O(N^3)
优化:将数组中的每个元素用标记数组标记一下,f[i]=1表示值为i的元素出现过,这样第三层循环就被优化了,时间复杂度O(N^2)。
注意:本题会出现重复计算,例如7=2+5同时7=3+4,这样7就被算了两次。所以当7被计算一次后,
f[7]要置为0,防止重复计算。
参考代码:
#include<bits/stdc++.h>
using namespace std;
//f[i]标记数组,数字i是否出现过 1为出现过,数组大小要开到2000,
//两个数的和会>1000,防止下标越界
int a[1010],f[2010];
int main(){
int n,cnt=0;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
f[a[i]]=1; //标记值为i的数字出现过
}
//枚举:组合枚举,不考虑顺序AB组合和BA组合是一种
for(int i=1;i<n;i++){
for(int j=i+1;j<=n;j++){
if(f[a[i]+a[j]]){ //a[i]+a[j]的和出现过
cnt++;
f[a[i]+a[j]]=0; //防止重复计算
}
}
}
cout<<cnt;
}