(OJ108)纯粹素数
问题描述
明明的爸爸是一位数学家,明明受他爸爸的影响从小就喜欢数学,经常向他爸爸请教数学问题。一天,明明问爸爸什么是素数,爸爸回答说:"首先,素数都是大于1的自然数;其次,素数是只能被1和其本身整除的数。例如'3'这个数,它只能被1和3这两个整数整除,因此'3'就是素数;但是'4'就不是素数,因为4除了能被1和4整除外,也能被2整除,因此'4'就不是一个素数。"
聪明的明明很快就理解了他爸爸的意思,于是又接着问他爸爸:"那么纯粹素数又是什么呢?"明明的爸爸接着回答说:"一个素数,去掉最高位,剩下的数仍为素数,再去掉剩下的数的最高位,余下的数还是素数,这样下去一直到最后剩下的个位数也还是素数,我们把这样的数称为纯粹素数。例如'1013'这个数,它只能被1和1013整除,因此'1013'是一个素数,我们去掉它的最高位,剩下的数是13(其实剩下的应该是013,但是前置0对一个整数来说没有意义,因此0被舍去,就剩下13),13只能被1和13整除,因此13也是个素数,我们再接着去掉它的最高位,剩下的个位数是3,3当然也是素数,因此'1013'就是纯粹素数。更有趣的是,1013是第一个大于1000的纯粹素数,因为:
-
1000能被1、2、......、1000整除,其本身不是素数;
-
1001能被1、7、......、1001整除,其本身不是素数;
-
1002能被1、2、......、1000整除,其本身不是素数;
-
1003能被1、17、......、1003整除,其本身不是素数;
-
1004能被1、2、......、1004整除,其本身不是素数;
-
1005能被1、3、......、1005整除,其本身不是素数;
-
1006能被1、2、......、1006整除,其本身不是素数;
-
1007能被1、19、......、1007整除,其本身不是素数;
-
1008能被1、2、......、1008整除,其本身不是素数;
-
1009是一个素数,但是9能被1、3、9整除,不是素数;
-
1010能被1、2、......、1010整除,其本身不是素数;
-
1011能被1、3、......、1011整除,其本身不是素数;
-
1012能被1、2、......、1012整除,其本身不是素数;
所以从1000到1012,每个数都不是纯粹素数。"
明明对他爸爸的回答很满意,于是自己动手从1000开始寻找纯粹素数,不一会儿他就找到了20个纯粹素数,调皮的明明开始反过来考爸爸了,问他爸爸能否告诉他第2个大于1000的纯粹素数是哪个?第3个大于1000的纯粹素数是哪个?......明明的爸爸被这些突如其来的问题给难住了,他无法立刻回答出来,于是请求你帮助他回答明明的这些问题。
明明的问题可以归结为:跟据一个正整数n,求出从1,000开始从小到大的第n个纯粹素数。
输入说明
你写的程序需要从标准输入设备(通常为键盘)中读入多组测试数据,每组测试数据仅占一行,每行仅包括一个正整数n(1 ≤ n ≤ 20)。每组测试数据与其后一组测试数据之间没有任何空行,第一组测试数据前面以及最后一组测试数据后面也都没有任何空行。
输出说明
对于每一组测试数据,你写的程序需要计算出一组相应的运算结果,并将每组运算结果依次写入到标准输出设备(通常为启动该程序的文本终端,例如Windows中的命令行终端)中。每组运算结果为一个整数,即从1,000开始从小到大的第n个纯粹素数。。每组运算结果单独形成一行,其行首和行尾都没有任何空格,每组运算结果与其后一组运算结果之间没有任何空行,第一组运算结果前面以及最后一组运算结果后面也都没有任何空行。
输入范例
1
10
20
输出范例
1013
1607
2137
个人总结
这一题与之前的纯粹合数那一题思路类似,即通过把数字变成字符串,去除首位元素后再转化为数字来达到去除数字最高位的效果;这题直接用了stoi函数完成字符串与数字的转换。
代码
cpp
#include <bits/stdc++.h>
using namespace std;
bool solution1(int n){//判定一个数是否为素数
if(n <= 1){
return false;
}
for(int i = 2; i <= sqrt(n); i++){
if(n % i == 0){
return false;
}
}
return true;
}
bool solution2(int n){//判定是否为纯粹素数
string str = to_string(n);
while(str != ""){
if(!solution1(stoi(str))){
return false;
}
str.erase(0, 1);
}
return true;
}
int main(){
int n;
while(cin >> n){
int i = 1000;
while(n--){
while(i++){
if(solution2(i)){
break;
}
}
}
cout << i << endl;
}
}
(OJ109)大实数加法
问题描述
给你两个正的实数A和B,你的任务是计算出A+B的值。
输入说明
本题目包含T组测试数据。
每一组测试数据在一行里面包含两个长度不大于400的正实数A和B,A和B均无多余的前导0。
输出说明
对于每一组测试数据,请在一行里面输出输出A+B的值,行首与行尾均无空格。
运算结果最后的0(比如1.400)不需要输出(输出为1.4)。
输入范例
3
1.1 2.9
1.1111111111 2.3444323343
1 1.1
输出范例
4
3.4555434454
2.1
个人总结
1.大实数加法,不能用一般的float或double来存储,只能用字符串来存放。相比之前大整数相加,难点在于多了小数,且两个数的整数部分与小数部分可能都不相同,其中一个数可能没有小数而另一个数没有,因此这里采取补零的方法统一两数的长度。
2.用mid1与mid2标记两数的小数点位置,为了使格式变得统一,对于没有小数部分的数统一先加一个小数点。
3.补零顺序必须是先在高位补零,直到两数整数部分长度相同,此时两数的mid的值应该是相同的;再在低位补零,直到两数小数部分长度相同,此时两数的r值应该是相同的。
4.相加后别忘了去除末尾多余的'0'/'.'(会有多余的'.'可能是因为两个加数本来就是整数或两个小数加成了一个整数)。
代码
cpp
#include <bits/stdc++.h>
using namespace std;
string add(string str1, string str2){//两个字符串整数部分相加
int i = str1.size() - 1;
int j = str2.size() - 1;
int a = 0, b = 0, tmp = 0, num = 0;
string result = "";
while(i >= 0 || j >= 0){
if(str1[i] == '.'){
result.insert(0, ".");
i--;
j--;
continue;
}
if(i >= 0){
a = str1[i] - '0';
}else{
a = 0;
}
if(j >= 0){
b = str2[j] - '0';
}else{
b = 0;
}
num = a + b + tmp;
if(num <= 9){
tmp = 0;
}else{
tmp = 1;
num = num - 10;
}
result.insert(0, to_string(num));
i--;
j--;
}
return result;
}
int main(){
int n;
cin >> n;
while(n--){
string num1, num2;
cin >> num1 >> num2;
int l1 = 0, mid1, r1;
int l2 = 0, mid2, r2;
//找/添加小数点
for(int i = 0; i < num1.size(); i++){
if(num1[i] == '.'){
mid1 = i;
break;
}
}
if(num1[mid1] != '.'){
num1.append(".");
mid1 = num1.size() - 1;
}
for(int i = 0; i < num2.size(); i++){
if(num2[i] == '.'){
mid2 = i;
break;
}
}
if(num2[mid2] != '.'){
num2.append(".");
mid2 = num1.size() - 1;
}
//左添0
while(mid1 < mid2){
num1.insert(0, "0");
mid1++;
}
while(mid2 < mid1){
num2.insert(0, "0");
mid2++;
}
//右添零
r1 = num1.size() - 1;
r2 = num2.size() - 1;
while(r1 < r2){
num1.append("0");
r1++;
}
while(r2 < r1){
num2.append("0");
r2++;
}
// cout << num1 << endl << num2;
string s = add(num1, num2);
while(s[s.size() - 1] == '0' || s[s.size() - 1] == '.'){
s.erase(s.size() - 1, 1);
}
cout << s;
cout << endl;
}
return 0;
}
(OJ110)考试排名
问题描述
C++编程考试使用的实时提交系统,具有即时获得成绩排名的特点。它的功能是怎么实现的呢?
我们做好了题目的解答,提交之后,要么"AC",要么错误,不管怎样错法,总是给你记上一笔,表明你曾经有过一次错误提交,因而当你一旦提交该题"AC"后,就要与你算一算帐了,总共该题错误提交了几回。虽然你在题数上,大步地跃上了一个台阶,但是在耗时上要摊上你共花去的时间。特别是,曾经有过的错误提交,每次都要摊上一定的单位时间分。这样一来,你在做出的题数上,可能领先别人很多,但是,在做出同样题数的人群中,你可能会在耗时上处于排名的劣势。
例如:某次考试一共8题(A,B,C,D,E,F,G,H),每个人做的题都在对应的题号下有个数量标记,负数表示该学生在该题上有过的错误提交次数,但到现在还没有AC,正数表示AC所耗的时间,如果正数a跟上一对括号,里面有个整数b,那就表示该学生提交该题AC了,耗去了时间a,同时,曾经错误提交了b次(如果b为0则没有括号及b),因此对于下述输入数据:

若每次错误提交的罚分为20分,即每错误提交一次,在总耗时时增加20分钟,则其排名从高到低应该是这样的:
Josephus 5 376
John 4 284
Alice 4 352
Smith 3 167
Bob 2 325
Bush 0 0
输入说明
输入数据的第一行是考试题数n(1≤n≤12)以及单位罚分数m(10≤m≤20),每行数据描述一个学生的用户名(不多于10个字符的字串)以及对所有n道题的答题现状,其描述采用问题描述中的数量标记的格式,见上面的表格,提交次数总是小于100,AC所耗时间总是小于1000。
学生数小于100。
输出说明
将这些学生的考试现状,输出一个实时排名。实时排名显然先按AC题数的多少排,多的在前,再按时间分的多少排,少的在前,如果凑巧前两者都相等,则按名字的字典序排,小的在前。每个学生占一行,输出名字(10个字符宽,左对齐),做出的题数(2个字符宽,右对齐)和时间分(4个字符宽,右对齐)。除上面所描述的为了对齐输出的空格外,名字、题数和时间分相互之间有一个空格。
输入范例
8 20
Smith -1 -16 8 0 0 120 39 0
John 116 -2 11 0 0 82 55(1) 0
Josephus 72(3) 126 10 -3 0 47 21(2) -2
Bush 0 -1 -8 0 0 0 0 0
Alice -2 67(2) 13 -1 0 133 79(1) -1
Bob 0 0 57(5) 0 0 168 -7 0
输出范例
Josephus 5 376
John 4 284
Alice 4 352
Smith 3 167
Bob 2 325
Bush 0 0
个人总结
1.size_t是是C++里的一种无符号整数类型,专门用来表示大小,长度,下标等信息。
2.[](...,...)的形式是临时函数,这里用来划定排序的判断依据。
代码
cpp
#include <bits/stdc++.h>
using namespace std;
struct Student{
string name;
int solved = 0;
int totaltime = 0;
};
int main(){
int n, m;
cin >> n >> m;
string name;
vector<Student> students;
while(cin >> name){
Student stu;
stu.name = name;
for(int i = 0; i < n; i++){
string s;
cin >> s;
if(s[0] == '-' || s[0] == '0'){
continue;
}
stu.solved++;
int time = 0;
int wrong = 0;
size_t pos = s.find('(');
if(pos == string::npos){
time = stoi(s);
}else{
time = stoi(s.substr(0, pos));
int end_pos = s.find(')');
wrong = stoi(s.substr(pos + 1, end_pos - pos - 1));
}
stu.totaltime += time + wrong * m;
}
students.push_back(stu);
}
sort(students.begin(), students.end(), [](const Student &a, const Student &b){
if(a.solved != b.solved){
return a.solved > b.solved;
}
if(a.totaltime != b.totaltime){
return a.totaltime < b.totaltime;
}
return a.name < b.name;
});
for(auto &stu : students){
cout << left << setw(10) << stu.name << " " << right << setw(2) << stu.solved << " " << right << setw(4) << stu.totaltime
<< endl;
}
return 0;
}
英语翻译
计算机科学可以分为四个主要领域:软件开发、计算机体系结构(硬件)、人机交互(为人类设计最高效的计算机使用方式)以及人工智能(试图让计算机表现出智能行为)。软件开发关注创建高效运行的计算机程序。计算机体系结构则致力于为特定的计算需求开发最优的硬件。人工智能和人机交互领域通常既涉及软件的开发,也涉及硬件的设计,以解决特定问题。
在开发计算机软件时,计算机科学家和工程师会研究软件设计的各个领域和技术,例如在特定程序中应使用哪种编程语言和算法最为合适,如何高效地存储和检索信息,以及某些软硬件组合所存在的计算极限。软件设计人员在开发程序时必须考虑许多因素。通常,为了保证软件的整体性能,某一方面的性能可能需要作出牺牲。例如,由于计算机的内存容量有限,软件设计人员必须限制程序所包含的功能数量,使其所需内存不超过目标系统所能提供的容量。
软件工程是软件开发的一个领域,在这一领域中,计算机科学家和工程师研究各种方法和工具,以促进正确、可靠且健壮的计算机程序的高效开发。该分支的研究涵盖软件生命周期的所有阶段,软件生命周期始于对问题的正式说明,随后进入解决方案的设计、将其实现为程序、对程序进行测试以及后期的维护。软件工程师开发各种软件工具以及称为编程环境的工具集合,以改进开发过程。例如,这些工具可以帮助管理由程序员团队编写的大型程序中的众多组成部分。
英语单词
