写题日记#1

洛谷P1909

题目描述

P 老师需要去商店买 n 支铅笔作为小朋友们参加 NOIP 的礼物。她发现商店一共有 3 种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同。为了公平起见,P 老师决定只买同一种包装的铅笔。

商店不允许将铅笔的包装拆开,因此 P 老师可能需要购买超过 n 支铅笔才够给小朋友们发礼物。

现在 P 老师想知道,在商店每种包装的数量都足够的情况下,要买够至少 n 支铅笔最少需要花费多少钱。

输入格式

第一行包含一个正整数 n ,表示需要的铅笔数量。

接下来三行,每行用2个正整数描述一种包装的铅笔:其中第 1 个整数表示这种包装内铅笔的数量,第 2 个整数表示这种包装的价格。

保证所有的 7 个数都是不超过 10000 的正整数。

输出格式

1 个整数,表示 P 老师最少需要花费的钱。

解题过程

思路:因为有三种铅笔都有,每种都有四个量,用四个数组存放四组量:dan每盒的铅笔数量,p每盒铅笔价钱,he至少购买的盒数,sum总价

第一次写出来的:

#include<iostream>
using namespace std;
int main(){
	int n;
	cin>>n;
	int dan[4],p[4],he[4],sum[4];
	for(int i=1;i<=3;i++){
		cin>>dan[i]>>p[i];
		he[i]=n/dan[i];
		if((n%dan[i])!=0){
			he[i]++;
		}
		sum[i]=he[i]*p[i];
	}
	int min=sum[1];
	for(int i=2;i<=3;i++){
		min=min<sum[i]?min:sum[i];
	}
	cout<<min;
}

第一次提交犯了个小错误:定义数组时[ ]内的是数组长度。调用数组时[ ]内是数组索引,如长度为4时,最大索引只有到3。

终于AC后,思考是否可以用某些函数简化一些操作,在题解中发现了ceil函数,也就是向上取整,正好可以优化我的代码中判断整盒购买是否整除的部分。向上取整ceil和向下取整floor都在库<cmath>中,记得将运算结果换为浮点,这两个函数才起作用ovo

第二次写出来的:

#include<iostream>
#include<cmath>
using namespace std;
int main(){
	int n;
	cin>>n;
	int dan[4],p[4],he[4],sum[4];
	for(int i=1;i<=3;i++){
		cin>>dan[i]>>p[i];
		he[i]=ceil(n*1.0/dan[i]);
		sum[i]=he[i]*p[i];
	}
	int min=sum[1];
	for(int i=2;i<=3;i++){
		min=min<sum[i]?min:sum[i];
	}
	cout<<min;
}

好吧,我承认这是很简单的一道题,但是总是很担心自己的基础,也确实在写这些题中犯了很多小错误,就当查缺补漏的练习吧awa

洛谷P1089

题目描述

津津的零花钱一直都是自己管理。每个月的月初妈妈给津津 300 元钱,津津会预算这个月的花销,并且总能做到实际花销和预算的相同。

为了让津津学习如何储蓄,妈妈提出,津津可以随时把整百的钱存在她那里,到了年末她会加上 20% 还给津津。因此津津制定了一个储蓄计划:每个月的月初,在得到妈妈给的零花钱后,如果她预计到这个月的月末手中还会有多于 100 元或恰好 100 元,她就会把整百的钱存在妈妈那里,剩余的钱留在自己手中。

例如 11 月初津津手中还有 83 元,妈妈给了津津 300 元。津津预计11月的花销是 180 元,那么她就会在妈妈那里存 200 元,自己留下 183 元。到了 11 月月末,津津手中会剩下 3 元钱。

津津发现这个储蓄计划的主要风险是,存在妈妈那里的钱在年末之前不能取出。有可能在某个月的月初,津津手中的钱加上这个月妈妈给的钱,不够这个月的原定预算。如果出现这种情况,津津将不得不在这个月省吃俭用,压缩预算。

现在请你根据 2004 年 11 月到 12 月每个月津津的预算,判断会不会出现这种情况。如果不会,计算到 2004 年年末,妈妈将津津平常存的钱加上 20% 还给津津之后,津津手中会有多少钱。

输入格式

12 行数据,每行包含一个小于 350 的非负整数,分别表示 11 月到 12 月津津的预算。

输出格式

一个数字。如果不会不高兴则输出 0,如果会则输出最不高兴的是周几(用 1,2,3,4,5,6,7 分别表示周一,周二,周三,周四,周五,周六,周日)。如果有两天或两天以上不高兴的程度相当,则输出时间最靠前的一天。

解题过程

又是查缺补漏的一道简单题,又不出意料的犯了低级语法错误o(╥﹏╥)o

思路:三个vector数组:out每月预算支出,shou每月手中的钱,cun存的钱。out由输入读取,shou初始化为300,因为每个月都会得到300元,对这两个数组的同一索引(即同一月份)下的数据进行巴拉巴拉的加减乘除后,百元大钞加到cun里,剩的零钱加到下一个月(shou的下一索引)。

没什么好的想法了,故最终版本为:

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int>  out(15,0);
	vector<int> shou(15,300);
	vector<int> cun(15,0);
	int pan=0,sum=0;
	for(int i=0;i<=11;i++)
	{
		cin>>out[i];
	}
	for(int i=0;i<=11;i++)
	{
		int sheng=shou[i]-out[i];
		if(sheng>0)
		{
			sum+=sheng/100*100;
			shou[i+1]+=sheng%100;
		};
		if(sheng<0){
			pan=i+1;
			break;
		}
	}
	if(pan)
	{
		cout<<-pan;
		return 0;
	}
	else
	{
		cout<<sum*1.2+shou[12]-300;
		return 0;
	}
}

刚刚摸鱼看了一些C语言趣味故事,才知道左花括号的位置还区分出了两种代码风格,然后发现自己一直写的是K&R风格,故在此尝试微软风格,对称的花括号看起来果然更舒服了(^▽^)

总结

题目较复杂时,尝试在草稿纸上模拟过程,寻找关系,不要一直发呆(ーー;)

洛谷P1035

题目描述

已知:Sn​=1+21​+31​+…+n1​。显然对于任意一个整数 k,当 n 足够大的时候,Sn​>k。

现给出一个整数 k,要求计算出一个最小的 n,使得 Sn​>k。

输入格式

一个正整数 k

输出格式

一个正整数 n。

解题过程

写完这题更是坚定了我要买《C Primer Plus》的决心,WA的原因全是因为小语法毛病……

很简单的题目,用模拟尝试到满足条件即可:

//模拟
#include<iostream>
using namespace std;
int main()
{
	int n=1,k;
	double sum=0;//当k较大时,flout精度不够
	cin>>k;
	while((sum+=1.0/n)<=k)//注意用1.0隐性转换
	{
		n++;
	}
//	for(double sum=0;(sum+=1.0/n)<=k;n++);另一种循环方式
	cout<<n;
	return 0;
}
美美AC后在题解区发现了更强的数论做法,故在理解后记录:
//数论
#include<iostream>
#include<cmath>
using namespace std;
int main() 
{
    double gamma=0.5772156649;
    int k,n;
    cin>>k;
    n=exp(k-gamma)+0.5;//exp函数用于求自然底数e的次方,括号内可接受整形或浮点型数据
    cout<<n;
    return 0;
}

n的式子由调和级数求和公式推导得来,虽然还是有很多疑问比如在C语言截断式取整的情况下为什么+0.5就能不出错balabala,略得出调和级数求和公式存在误差的结论,不深究了反正该方法就当拓展吧。

总结

除了暴力模拟,可以尝试思考题目中的数学原理,用数学知识优化代码。

(不会告诉你本人为此已花两小时研究数论且一无所获)

洛谷P1980

题目描述

试计算在区间 1 到 n 的所有整数中,数字 x(0≤x≤9)共出现了多少次?例如,在 1 到 11 中,即在 1,2,3,4,5,6,7,8,9,10,11 中,数字 1 出现了 4 次。

输入格式

2 个整数 n,x,之间用一个空格隔开。

输出格式

1 个整数,表示 x 出现的次数。

解题过程

第一反应是用取模取整运算分离数字各个数位:

#include<iostream>
using namespace std;
int main() 
{
    int n=0,x=0,k=0;
    cin>>n>>x;
    for(int i=1;i<=n;i++)
	{
	    int m=i;
	    while(m>0)
	    {
		if(m%10==x)
	        {
		    k++;
	        }
	    m=m/10;
	    } 
	}
    cout<<k;
    return 0;
}

不出意外的话又出意外了,我的第一版代码在循坏内部直接对 i 进行处理导致其值改变,影响循环条件,直接TLE了,已对自己无奈ヽ(ー_ー)ノ

然后学了一些string容器函数,有了以下写法:

#include<iostream>
#include<cmath>
#include<sstream>
#include<algorithm>
using namespace std;
int main() 
{
    int n=0,x=0,k=0;
    cin>>n>>x;
    for(int i=1;i<=n;i++)
    {
    	string s=to_string(i);//int转换为string
    	for(int j=0;j<s.size();j++)
    	{
    		if(s[j]==x+'0')//s[j]为字符,应将x转换为字符再比较
    		{
    			k++;
			}
		}
	}
	cout<<k;

}

怎么感觉还是很复杂,于是又找到了个函数:count

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main() 
{
	int n=0,x=0,k=0;
	string s;
	cin>>n>>x;
	for(int i=1;i<=n;s+=to_string(i),i++);
	k=count(s.begin(),s.end(),x+'0');
	cout<<k;
	return 0;
}

头文件kuku引,代码kuku改,怎么看起来头重脚轻的[・_・?]

总结

灵活选择使用适合的C++函数,可以极大的简化代码,达到效果。

洛谷P1014

题目描述

现代数学的著名证明之一是 Georg Cantor 证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:

我们以 Z 字形给上表的每一项编号。第一项是 1/1,然后是 1/2,2/1,3/1,2/2,…

输入格式

整数N(1≤N≤107)。

输出格式

表中的第 N 项。

解题过程

看着这别扭的排布,灵机一动,脖子一歪,看成斜着的一行行数字,观察到行数、项数与分子分母之间的关系,故有第一版代码:

#include<iostream>
using namespace std;
int main()
{
	int zi=1,mu=1;
	int n,hang=1;
	cin>>n;
	while((n-hang)>0)
	{
		n=n-hang;
		hang++;
	}
	if(hang%2==0)
	{
		mu=hang;
		mu=mu-(n-1);
		zi=zi+(n-1);
	}
	else
	{
		zi=hang;
		zi=zi-(n-1);
		mu=mu+(n-1);
	}
	cout<<zi<<'/'<<mu; 
}

感觉变量太多了,重复的部分也很多,似乎可以用n和hang代替zi和mu,尝试列关系式替换来化简,于是得到了非常简洁的第二版:

#include<iostream>
using namespace std;
int main()
{
	int n,hang=1;
	cin>>n;
	for(;n-hang>0;n-=hang,hang++);
	if(hang%2==1)
	cout<<hang-(n-1)<<'/'<<n; 
	else
	cout<<n<<'/'<<hang-(n-1);
	
}

总结

寻求变量间的关系,利用关系式可以替换化简多余的部分。

洛谷P1014

题目描述

给定一个整数 N,请将该数各个位上数字反转得到一个新数。新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零(参见样例 2)。

输入格式

一个整数 N

输出格式

一个整数,表示反转后的新数。

解题过程

刚开始思考半天字符串的解法,又要反转又要消0,最后还是用取模取整运算写了(参考了题解)

#include<bits/stdc++.h>
using namespace std;
int n,s=0;
int main()
{
    cin>>n;
    while(n) s=s*10+n%10,n/=10;
    cout<<s;
    return 0;
}

看完之后真的直呼精彩,六道题里第一个这么让我哇塞的,妙啊妙啊喵啊~

可以思考一下为什么正负数情况通用,且不用单独写代码消0

总结

没有总结,多欣赏简洁的代码对身心健康有好处

END

看似一篇日记,实际写了两天,六道题让自己无比稀碎的语言基础暴露无遗(T_T)。这是我的博客第一篇与

Yu感谢你的阅读ovo
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇