实验任务
hbb 学长受邀去帮电影《神奇犇犇在哪里》卖门票,售票口有n个人排队等待买票。已知每张门票售价25 元,排队的每个人手上只有25, 50, 100 面值的钞票。一开始hbb 学长在售票处所拥有的钱为0(没有多余的零钱),且n 个人必须按顺序买票。请你判断hbb学长能否成功卖出所有门票。
数据输入
第一行一个n (1 ≤ n ≤ 100)。表示数组元素个数。
第二行n 个整数,表示数组a1, a2, …, an。(ai =25,50,100)
数据输出
输出YES 或者NO。
样例
输入示例
4
25 25 50 50
输出示例
YES
输入示例
2
25 100
输出示例
NO
Code
#include
int main (void)
{
short n,i;
short a[2]={0};
scanf("%hd",&n);
for (i=1;i<=n;i++)
{
short t;
scanf("%hd",&t); //读取支付面额
switch (t)
{ //相应面额的张数+1,因为找钱用不到100面额,所以不计算100面额张数
case 25 :a[0]++; break; //25面额张数+1
case 50 :a[1]++; break; //50面额张数+1
}
short money=t-25; //money为应找钱数
switch (money)
{
case 25 : //应找25元,则只有一种方案
{
if (a[0]<1) //如果25面额不足1张,则无法找零
{
printf("NO\n"); return 0;
}
else
a[0]--; //如可以找零,则25面额张数-1
}
break;
case 75: //应找75元,则有两种方案:1、50+25;2、25*3
{ //有50的情况下先给50,25尽量留着,因为上面一种情况需要用到25
if (a[1]>0 && a[0]>0) //若有一张50,一张25,则可找零
{
a[1]--; a[0]--;
}
else if (a[0]>2) //若有三张25,则可找零
a[0]-=3;
else //否则,不可找零
{
printf("NO\n"); return 0;
}
}
break;
}
}
printf ("YES\n");
return 0;
}
实验任务
浴盆学长喜欢玩滑来滑去的游戏。他写下n 个数的数组a,a1, a2, …, an。每个数不是0 就是1。他可以做一次操作:给定i 和j(1 ≤ i ≤ j ≤ n),把数组区间[i, j]中的所有数ak 变成1-ak(i≤k≤j)。他想考一考负一号学长,该怎样选择i 和j 才能使操作之后的数组中的1 的数量最多。但是负一号学长觉得这题太简单了,他懒得秒了它,所以就只能由你来和浴盆学长玩这个游戏了。
数据输入
第一行一个n (1 ≤ n ≤ 100)。表示数组元素个数。
第二行n 个数,表示数组a1, a2, …, an。
数据输出
输出一次操作能得到的最大的1 的个数。
样例
输入示例
5
1 0 0 1 0
输出示例
4
输入示例
4
1 0 0 1
输出示例
4
Hint
样例1:i=2,j=3 或i=2,j=5
样例2:i=2,j=3
Code
#include
int main (void)
{
short n,i;
scanf("%hd",&n);
short min=0,num=0,one=0; //min为子序列和最小值,num为子序列和,one为1的个数
for (i=1;i<=n;i++)
{
short t;
scanf("%hd",&t); //读取数字
if (t) //如果数字是1
{
num++; one++; //子序列和+1,1的个数+1
}
else
num--; //否则,子序列和-1
if (num//如果子序列和小于最小值
min=num; //最小值更新
else if (num>0) //如果子序列和>0
num=0; //则清零子序列和
}
if (min==0) printf("%d\n",n-1); //对于n个数全是1的情况,因为至少进行一次操作,所以输出n-1
else printf("%d\n",one-min); //其他情况,输出1的个数减去最小值(最小值<0)
return 0;
}
此题把0看作是-1,即可当作是求n个数中子序列和的最小值,如:
0 序列和= -1, 将整个序列反转:1 ,则1的个数可+1(即-(-1))
0 1 序列和= 0, 将整个序列反转:1 0 ,则1的个数可+0(即-(0))
0 1 0 序列和= -1, 将整个序列反转:1 0 1 ,则1的个数可+1(即-(-1))
0 0 1 0 0 序列和= -3, 将整个序列反转:1 1 0 1 1 ,则1的个数可+3 (即-(-3))
因而,子序列和越小,将这个子序列反转之后,1的个数就可加得越多。
寻找最小子序列和,则使用一重循环,当前序列和加上下一个数(0当作-1),若序列和小于最小值,则更新最小值,若序列和大于0,说明此序列再减1不如直接从0减1,即清零子序列,序列起点从下一个数开始。
但还有一个值得注意的点,题目要求至少要做一次操作,所以像
1
1
这样的输入数据,输出应该是0
而不是1
。同理,对于全是1的n个数,至少进行一次操作,即把其中一个1变为0是最优解,所以输出应为n-1。
实验任务
Ogo 星球的人当然说的是ogo 语言。Ogo 语言只由ogo,ogogo,ogogogo,…..等单词组成(这些单词也被称为ogo 单
词)。现在负一号学长被安排去给ogo 星球的军队做文件加密工作,这项工作的内容是把一段字符串中的ogo 单词全部替换成*。负一号学长觉得这些超级简单,所以他懒得做,你能帮负一号学长完成任务吗?
数据输入
第一行输入一个n(1≤n≤100),表示字符串的长度。
第二行输入一个字符串(只由小写字母组成)。
数据输出
输出转换后的字符串。
样例
输入示例
7
aogogob
输出示例
a***b
输入示例
15
ogogmgogogogogo
输出示例
***gmg***
输入示例
9
ogoogoogo
输出示例
*********
Hint
第一个样例中的ogo 单词是ogogo,第二个样例中的ogo 单词是ogo和ogogogogo。
Code
#include
int main (void)
{
short n;
char s[110];
scanf("%hd",&n);
scanf("%s",s);
short i=0; //记得初始化
while (i//从头遍历
{ //当找到“ogo”时,输出“***”,且i+3
if (s[i]=='o' && s[i+1]=='g' && s[i+2]=='o')
{
printf("***");
i+=3;
while (s[i]=='g' && s[i+1]=='o') //看“ogo”后面有没有“go”
i+=2; //有的话i+2
}
else
{ //如果不是“ogo”,原样输出,且i+1
printf("%c",s[i]);
i++;
}
}
printf("\n");
return 0;
}
实验任务
尾行学姐喜欢由1, 14, 144 组成的数,比如14144, 141414 和1411 是她喜欢的数,但是1444, 514 和414 不是。给出一个数,请你判断尾行学姐喜不喜欢这个数。
数据输入
第一行输入一个n(1≤n≤10 9 )。
数据输出
如果尾行学姐喜欢这个数,输出YES,否则输出NO。
样例
输入示例
114114
输出示例
YES
输入示例
1111
输出示例
YES
输入示例
441231
输出示例
NO
Code
#include
int main (void)
{
char s[15];
scanf("%s",s);
short i=0;
while (s[i]!='\0')
{
if (s[i]=='1')
{ //如果是‘1’,i+1
i++;
if (s[i]=='4') //‘1’后面如果是‘4’,i再+1
{
i++;
if (s[i]=='4') //‘4’后面如果是‘4’,i再+1
i++;
}
}
else
{ //否则,直接输出‘NO’
printf("NO\n");
return 0;
}
}
printf("YES\n");
return 0;
}
实验任务
浴盆学长喜欢玩序列,他想找出一个序列中具有周期性的元素和它的周期。负一号学长决定帮浴盆学长找,但是这题实在是太简单了,负一号学长懒得秒了它,现在就只能由你来做了。现在你要在一组数的序列{a1, a2, …, an}中找到所有符合下列条件的元素x:
1,该元素x 是{a1, a2, …, an}中的一个数;
2,该元素x 在序列中重复出现,且该元素重复出现的相邻间隔全都相同。若该元素x 只出现一次,则假设它的间隔为0。
3,符合条件2 的元素间隔,即为元素x 的周期y。
数据输入
第一行一个n (1 ≤ n ≤ 100)。表示数组元素个数。
第二行n 个整数,表示数组a1, a2, …, an。(1 ≤ ai ≤ 100000)
数据输出
输出m。表示有m 个元素有周期性。
以下m 行,每行输出两个数x, y,表示元素x 的周期是y。(请按照x 的大小升序输出答案。)注意如果元素只出现一次,也具有周期性,且周期是0。
样例
输入示例
6
1 2 2 1 1 2
输出示例
0
输入示例
8
1 2 1 3 1 2 1 5
输出示例
4
1 2
2 4
3 0
5 0
Hint
1,“1”重复出现了三次,但它们之间的间隔分别为3 和1,间隔不一致,所以“1”没有周期性。“2”重复出现了三次,它们之间的间隔分别为1 和3,所以“2”也没有周期性。综上,序列中不存在任何元素具有周期性。
2,“1”重复出现了四次,间隔均为2,所以“1”的周期为2;“2”重复出现了两次,间隔为4,因此周期为4;“3”和“5”都只出现了一次,因此根据题目假设,周期为0。
Code
#include
#include
#include
using namespace std;
struct aa
{
int value; //这个数字的值
short site; //这个数字上次出现的位置
int period; //这个数字的周期,当period=-1时表示这个数字不具周期性
};
aa a[110]; //a[]记录可能具有周期性的数字
int cmp(aa a1,aa a2) //sort排序函数
{
return a1.value//以成员value作为排序标准,升序排序
}
int main (void)
{
short n,m=0,no_m=0; //m为出现的数字,no_m为不具周期性的数字
short i,j;
scanf("%hd",&n);
for (i=1;i<=n;i++)
{
int t;
scanf("%d",&t);
short ok=1; //ok表示这个数字t是否已被a[]记录过
for (j=1;j<=m;j++) //循环所有已记录过的数字
{
if (a[j].value==t) //如果数字t已记录过
{
if (a[j].period!=-1) //如果这个数字不是非周期性数字
{
if (a[j].period==0) //如果这个数字之前只出现一次
{
a[j].period=i-a[j].site; //那这个数字周期设为i减去之前出现的位置
a[j].site=i; //更新数字最后出现的位置
}
else if (a[j].period==i-a[j].site) //如果这个数字的周期不变
a[j].site=i; //更新数字最后出现的位置
else //如果这个数字的周期改变
{
a[j].period=-1; //这个数字不具周期性
no_m++; //不具周期性数字个数+1
}
}
ok=0; //数字t已被记录过
}
}
if (ok) //如果数字t没被记录过
{
m++; //记录数字个数+1
a[m].value=t; //记录这个数字的值
a[m].site=i; //记录这个数字最后出现的位置
a[m].period=0; //首次出现,周期为0
}
}
sort(a+1,a+m+1,cmp); //对所有记录过的数字以value为标准进行升序排序
printf("%d\n",m-no_m); //输出具有周期性数字的个数
for (i=1;i<=m;i++)
if (a[i].period!=-1) //如果这个数字具有周期性
printf("%d %d\n",a[i].value,a[i].period);
return 0;
}
实验任务
负一号学长总是玩奇怪的游戏。今天他玩的游戏叫做insert。Insert 游戏是这样的:给出一个数组a[1~n](a 数组是1~n 的一种排列),负一号学长每次取出a 数组的最后一个元素,再把它插入到a数组中。请问你,负一号学长最少要执行几次操作,才能把a 数组变成b 数组呢?
数据输入
第一行一个n (1 ≤ n ≤ 100)。表示数组个数。
第二行n 个数,表示数组a1, a2, …, an。
第三行n 个数,表示数组b1, b2, …, bn。
数据输出
输出最少操作次数。
样例
输入示例
3
3 2 1
1 2 3
输出示例
2
输入示例
5
1 5 2 3 4
1 2 3 4 5
输出示例
3
Hint
样例2 操作过程如下
Code
#include
int main (void)
{
short n,i,j=1;
scanf("%hd",&n);
short a[110],b[110];
for (i=1;i<=n;i++)
scanf("%hd",&a[i]);
for (i=1;i<=n;i++)
scanf("%hd",&b[i]);
i=1; //i和j都从1开始
short step=0; //步数
while (j<=n)
{
if (a[i]!=b[j]) //如果a[i]和b[j]不相等
{
j++; //j递增
step++; //步数+1
}
else //如果两者相等,i和j都+1
{
i++; j++;
}
}
printf("%d",step);
return 0;
}
从a末尾去元素插入到数组a中,其实和从b数组中拿一个元素放到数组b末尾是一样的,所以就看b数组中哪些数字要拿到末尾,使得最终转换成a数组。
于是用两个指针 i 和 j 指向数组a的第 i 位和数组b的第 j 位,若两者相等,i 和 j 都+1,当两者不相等时,j 一直递增,直到b[j]等于a[i],则b[j]到b[i]之间的数字都需要拿到末尾,数字个数即为完成这个过程的步数,之后 i 和 j 再都+1,以此类推。
实验任务
盆盆学长不喜欢浮点数。他现在有一个大小为2n 的数列,数列元素都是浮点数(保留到小数点后三位)。盆盆学长决定把这个数列的元素都变成整数。变换规则是:取出n 个数向下取整,剩下n 个数向上取整。(例:2.5 向上取整是3,向下取整是2)但是如果变换之后的数列的和与变换前数列的和相差太多,盆盆学长会伤心。请你找出变换前后和相差最小的方案,并输出相差了多少(保留到小数点后三位)。
数据输入
第一行一个n (1 ≤ n ≤ 100)。表示数组元素个数。
第二行2n 个整数,表示数组a1, a2, …, an。(0 ≤ ai ≤ 10000)
数据输出
输出ans(保留到小数点后三位)。
样例
输入示例
3
0.000 0.500 0.750 1.000 2.000 3.000
输出示例
0.250
Hint
| (0 + 0.5 + 0.75 + 1 + 2 + 3) - (0 + 0 + 1 + 1 + 2 + 3) | = 0.25
Code
#include
#include
int main (void)
{
short n;
scanf("%hd",&n);
short nn=2*n,i,one=0; //one为小数部分为.000的数的个数
double ans=0.0;
for (i=1;i<=nn;i++)
{
double t;
scanf("%lf",&t);
if ( fabs(fmod(t,1)-0.0) < 1e-8 ) //fmod为浮点数求余,浮点数作差判断是否相等
one++; //若小数部分为.000,one+1
ans+=fmod(t,1); //ans为所有小数部分之和
}
double min=200.0,temp;
if (one<=n) //如果小数部分为.000的数的个数小于等于总数nn的一半
for (i=n-one;i<=n;i++) //-1的个数范围从n-one到n
{
temp=ans-i;
if ( fabs(temp) < min )
min=fabs(temp); //枚举得到最小值
}
else //如果小数部分为.000的数的个数大于总数nn的一半
for (i=0;i<=nn-one;i++) //-1的个数范围从0到nn-one
{
temp=ans-i;
if ( fabs(temp) < min )
min=fabs(temp);
}
printf("%.3f\n",min); //保留三位小数输出
return 0;
}
若一个数小数部分为x,
则可得出结论,在不存在小数部分为.000的数时,对所有的2n个数,无论向上取整还是向下取整,
而若存在小数部分为.000的数时,因为这样的数向上取整之后,原数 - 现数 = 0.000 = x ,并不会再 -1,所以可根据将 小数部分为.000的数 向上取整的个数来调节-1的个数
若小数部分为.000的数的个数one
小于等于n
则可向上取整的 小数部分非.000的数 的个数最少为n-one
,最大为n
,即-1
的个数为最少为n-one
,最大为n
。
若小数部分为.000的数的个数one
大于n
则可向上取整的 小数部分非.000的数 的个数最少为0
,最大为nn-one
,即-1
的个数为最少为0
,最大为nn-one
。
最后枚举得出绝对值最小的值。