PTA天梯赛练习集 L1-046 整除光棍 (20 分)

本文探讨了一种特殊的数字——光棍数,即由连续的1组成的数,并提出了一种算法,通过输入一个特定的奇数,找到能被该奇数整除的最小光棍数及其位数。文章详细解释了算法的实现过程,包括如何使用数组处理大数值,以及如何判断光棍数是否满足条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里所谓的“光棍”,并不是指单身汪啦~ 说的是全部由1组成的数字,比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13整除。 现在,你的程序要读入一个整数x,这个整数一定是奇数并且不以5结尾。然后,经过计算,输出两个数字:第一个数字s,表示x乘以s是一个光棍,第二个数字n是这个光棍的位数。这样的解当然不是唯一的,题目要求你输出最小的解。

提示:一个显然的办法是逐渐增加光棍的位数,直到可以整除x为止。但难点在于,s可能是个非常大的数 —— 比如,程序输入31,那么就输出3584229390681和15,因为31乘以3584229390681的结果是111111111111111,一共15个1。

输入格式:

输入在一行中给出一个不以5结尾的正奇数x(<1000)。

输出格式:

在一行中输出相应的最小的s和n,其间以1个空格分隔。

输入样例:

31

输出样例:

3584229390681 15

解题思路:

这道题的题目很容易理解,在难点上,题目也给了很明确的提示(题目已经说了s可能是个很大的数,这表示一定有一个测试点是一个位数相当大的,由于位数的原因,所以我们要用数组来保存这个位数很大的数,比如题目上的3584229390681)

代码实现:

#include<bits/stdc++.h>
using namespace std;
int main(){
	string a="1";
	int x,h;
	vector<int> b;
	cin>>x;
	while(1){//进入死循环 ,第一次为1,第二次为11,之后每次位数加1,下面会有详解 
		vector<int>().swap(b);//这条语句的作用是将数组b清空 ,swap()函数是交换两个数组的值,
							//这里是将数组b中的值与空数组交换了 
		h=0;//h为余数,第一次为0
		int i;
		for(i=0;i!=a.size();i++){//这个循环的作用是将光棍数除以x,并将结果保存在数组b中,
								//之所以用数组是因为光棍数可能是一个很大的值,无法用一个变量保存 
			b.push_back(((int)a[i]-48+h*10)/x);//h为上一位的余数,第一次为0 
			h=((int)a[i]-48+h*10)%x;//求出本位的余数, 
		}
		if(h==0){//经过for循环后,h仍未0的话,说明此次的while循环中的光棍数被x整除,则此次数组b中保存的值为题目要求的s 
			for(int j=0,flag=0;j!=b.size();j++){
				if(b[j]!=0){//flag的作用是输出时不输出前导0,如数组b保存的数可能是00003584229390681(因为是用数组保存的数,所以存在前导0) 
					flag=1;
				}
				if(flag){
					cout<<b[j];
				}
			}
			cout<<" "<<a.size();//a.size()所得的是字符串a的长度,即题目中要求输入的n 
			return 0;//结束函数,此时输出的便是光棍数最小的情况 
		}else{//h不等于0,代表此次while循环的光棍数不能被x整除, 
			a+="1";//在原来的基础上乘10,再在个位数上+1,比如1变为11; 11变为111; 
		}
	}
}
### 解决方案 对于PTA天梯赛训练中的L1-009 N个数求和问题,在C++中可以通过定义结构体来存储数并编写函数处理加法运算以及化简操作。下面展示了一个完整的解决办法。 #### 定义数据结构与辅助功能 为了方便表示数,可以创建一个名为`Fraction`的结构体用于保存(`numerator`)(`denominator`)两个成员变量;同时提供构造函数初始化对象,并重载流插入运算符以便于输出显示[^1]。 ```cpp #include <iostream> using namespace std; struct Fraction { int numerator; int denominator; // 构造函数 Fraction() : numerator(0), denominator(1) {} Fraction(int num, int deno): numerator(num), denominator(deno){ simplify(); } void simplify(){ if (this->denominator != 0 && this->numerator != 0){ int gcd_val = __gcd(abs(this->numerator), abs(this->denominator)); this->numerator /= gcd_val; this->denominator /= gcd_val; if (this->denominator < 0){ // Ensure the sign is on top this->numerator *= -1; this->denominator *= -1; } }else{ this->numerator = 0; this->denominator = 1; } } friend ostream& operator<<(ostream &os, const Fraction &f); }; // Overload << to output fraction objects easily. ostream& operator<<(ostream &os, const Fraction &f){ os<< f.numerator << "/" << f.denominator; return os; } ``` #### 主逻辑实现 接下来是主程序部,这里读取输入直到遇到文件结束标志EOF为止。每次迭代都会先获取当前测试案例的数量n,之后循环读入每一个数字符串形式的数据转换为对应的`Fraction`实例加入到向量容器之中准备后续计算。最后遍历所有项累加得到最终结果后打印出来即可完成整个流程[^2]。 ```cpp int main() { vector<Fraction> fractions; while(true){ string line; getline(cin,line); if(line.empty()) break; stringstream ss(line); size_t count; ss >> count; for(size_t i=0 ;i<count;++i){ char slash; int numer, denom; ss>>numer>>slash>>denom; fractions.emplace_back(numer,denom); } // Calculate LCM of all denominators first long long lcm = 1LL *fractions.front().denominator; for(auto it=fractions.begin()+1;it!=fractions.end();++it){ lcm=(lcm*(*it).denominator)/__gcd(lcm , (*it).denominator ); } // Sum up all numerators after converting them into same base using calculated LCM long long total_numerator=0; for(const auto& frac:fractions){ total_numerator+=frac.numerator*(lcm/frac.denominator); } cout<<Fraction(total_numerator,lcm)<<endl; // Clear input buffer and prepare for next test case cin.clear(); cin.ignore(INT_MAX,'\n'); fractions.clear(); } return 0; } ``` 此段代码实现了对多个带符号有理数相加以获得其简化后的表达式的功能。通过构建合理的类封装了必要的属性和行为使得整体架构清晰易懂易于维护扩展[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值