🌼feels good😃串烧 - 许天昱/陈旭辉-nn/单子玹/蒋笛含 - 单曲 - 网易云音乐
🌼10道入门题 --- 明显比上篇博客难了一点,要慢慢做了
目录
一,第k个素数
二,最大公约数
三,最小公倍数
四,图像旋转
五,计算鞍点
六,幂字符串
七,同学分组
八,字符串排序
九,同构数
十,素数回文数的个数
总结
一,第k个素数
P1052 - 第k个素数 - New Online Judge (ecustacm.cn)
1,首先写个判断素数的函数
2,主函数里先对k = 1, k = 2判断,分别输出2和3
3,优化:
(1)judge()判断素数时,取余只需要到平方根
(2)主函数遍历时,3以后的偶数都不是素数
#include<iostream>
using namespace std;
int judge(int n) //判断素数
{
for(int i = 2; i*i <= n; ++i) {
if(n % i == 0) {
return false;
}
}
return true;
}
int main()
{
int i, k, c = 2; //第c个素数
cin>>k;
for(i = 3; c <= k; i += 2) { //3以后的偶数都不是素数
if(judge(i)) c++;
}
if(k == 1) cout<<2;
else if(k == 2) cout<<3;
else cout<<i - 2;
return 0;
}
二,最大公约数
P1053 - 最大公约数 - New Online Judge (ecustacm.cn)
1,公式:两数a, b,最大公约数p, 最小公倍数q,则 a * b = p * q
2, 两数公因子累乘可得最大公约数
3,辗转相除法(推荐)
比如26和39, 26 % 39 = 26 --> 39 % 26 = 13 --> 26 % 13 = 0, 所以最大公约数为13
就是用被取余的数,取余余数,当结果等于0, 此时被取余的数就是最大公约数
#include<iostream>
using namespace std;
int main()
{
int a, b;
while(cin>>a>>b) {
int temp = b;
while(temp) {
temp = a % b;
a = b;
b = temp;
}
cout<<a<<endl;
}
return 0;
}
三,最小公倍数
P1054 - 最小公倍数 - New Online Judge (ecustacm.cn)
通过最大公约数来求
注意单个数字最大10^9,所以乘积满足long long
#include<iostream>
using namespace std;
int main()
{
long long a, b;
while(cin>>a>>b) {
long long temp = b, pro = a * b;
while(temp) {
temp = a % b;
a = b;
b = temp;
}
cout<<pro / a<<endl;
}
return 0;
}
四,图像旋转
P1055 - 图像旋转 - New Online Judge (ecustacm.cn)
在草稿纸举个4行3列的例子后得到
旋转前的行标 + 旋转后列标 j - 1= 旋转前总行数(n)
旋转前的列标 = 旋转后的行标 i
所以,用旋转后的i, j表示出旋转前的i, j即可
输入a[i][j],输出a[n + 1 - j][i]
但仅这样,第一次Ac 7% ×,因为m, n的范围不对,只是在样例m = 3, n = 3的情况对了
cin>>n>>m;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
cin>>a[i][j]; //输入
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
cout<<a[n + 1 - j][i]<<" "; //输出
}
cout<<endl;
}
输出时需要m, n反过来 √
#include<iostream>
using namespace std;
int a[110][110];
int main()
{
int n, m;
cin>>n>>m;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
cin>>a[i][j]; //输入
for(int i = 1; i <= m; ++i){
for(int j = 1; j <= n; ++j){
cout<<a[n + 1 - j][i]<<" "; //输出
}
cout<<endl;
}
return 0;
}
延伸:矩阵的转置是逆时针旋转90°,而本题是顺时针旋转90°
五,计算鞍点
P1056 - 计算鞍点 - New Online Judge (ecustacm.cn)
考虑用ma[]数组保存每行最大值,mi[]数组保存每列最小值,然后ma[i] == mi[i]即可输出
#include<iostream>
#include<algorithm> //sort()
using namespace std;
int a[10][10], ma[10], mi[10];
int main()
{
int i, j;
for(i = 1; i <= 5; ++i)
for(j = 1; j <= 5; ++j)
cin>>a[i][j]; //输入矩阵
for(i = 1; i <= 5; ++i) {
int Max = -666666, Min = 666666;
for(j = 1; j <= 5; ++j){
Max = max(Max, a[i][j]);
Min = min(Min, a[j][i]);
}
ma[i] = Max; //第i行最大值
mi[i] = Min; //第j列最小值, 大坑:是mi[i]不是mi[j]
}
int flag = 1;
for(j = 1; j <= 5; ++j)
for(i = 1; i <= 5; ++i)
if(ma[i] == mi[j]) { //同时满足
cout<<i<<" "<<j<<" "<<ma[i];
flag = 0;
}
if(flag) cout<<"not found";
return 0;
}
六,幂字符串
P1057 - 幂字符串 - New Online Judge (ecustacm.cn)
1,本题核心:substr()函数,头文件是#include<cstring>,例如
#include<iostream>
#include<cstring> //s.substr()
using namespace std;
int main()
{
string s = "01234567", s1 = s.substr(5), s2 = s.substr(6, 2);
cout<<s<<endl<<s1<<endl<<s2;
return 0;
}
01234567
567
67
substr(i)表示从下标 i 开始到结尾,substr(i, j)表示从下标 i 开始截取 j 个字符
2,思路
(1)求连续相同的子串的数量,所以我们从一个字母开始截取,不一样就break
(2)从2个字母开始截取,如果2个字母的子串s1 == 后面每两个字母的子串s2,输出重复次数
(3)否则3个3个地截取......
第一次 Accepted 90%
#include<iostream>
#include<cstring> //s.substr()
using namespace std;
int main()
{
string s, s1, s2;
cin>>s;
int ans = 0, k = 1, len = s.size(); //k为子串长度
while(k < len) {
int j, flag = 1;
s1 = s.substr(0, k);
for(j = k; j < len; j += k) {
s2 = s.substr(j, k);
if(s1 != s2) {
flag = 0;
break;
}
else ans++; //子串出现次数
}
if(flag) break;
k++;
}
if(k == len) cout<<1;
else cout<<ans + 1; //加上第一个子串
return 0;
}
试出两组错误数据
aabaab
3
aaabaaab
4
原来是ans放在了while外面,导致aabaab中,前面的aa使输出多了1(常犯错误),务必每次更新
Accepted 100%
#include<iostream>
#include<cstring> //s.substr()
using namespace std;
int main()
{
string s, s1, s2;
cin>>s;
int ans, k = 1, len = s.size(); //k为子串长度
while(k < len) {
ans = 0; //每次都要清零
int flag = 1;
s1 = s.substr(0, k);
for(int j = k; j < len; j += k) {
s2 = s.substr(j, k);
if(s1 != s2) {
flag = 0;
break;
}
else ans++; //子串出现次数
}
if(flag) {
break;
}
k++;
}
if(k == len) cout<<1;
else cout<<ans +1;
return 0;
}
七,同学分组
P1058 - 同学分组 - New Online Judge (ecustacm.cn)
1,结构体联系同一组的名字
2,q次询问时遍历,比较两字符串相等,需要strcmp()函数,头文件#include<cstring>
strcmp(s1, s2),s1 == s2,输出 == 0; s1 > s2,输出 > 0; s1 < s2,输出 < 0;
给大家补充个:头文件#include<cstring>,常用函数有
strlen()求字符数组长度,strcmp()比较两字符串大小,memcpy()拷贝数组,字符串等,
memset()初始化数组,结构体等,strcpy(a, b)将字符串b拷贝到a
第一次报错error: from char to const char,因为把 if(!strcmp(s, a[j].s1)) 写成了 if(!strcmp(s[i], a[j].s1)),改正后运行错误 40%
第二次 运行错误 40% --> Ac 100% 原来是数组声明小了,struct group a[1010]; 写成了
struct group a[20]; (受名字20个字符的误导)
#include<iostream>
#include<cstring> //strcmp(),compare的意思
using namespace std;
struct group
{
char s1[20], s2[20];
};
int main()
{
int n, q;
cin>>n>>q;
struct group a[1010];
char s[20];
for(int i = 0; i < n; ++i)
cin>>a[i].s1>>a[i].s2; //输入名字
for(int i = 0; i < q; ++i) {
cin>>s;
for(int j = 0; j < n; ++j) {//遍历查找
if(!strcmp(s, a[j].s1)) cout<<a[j].s2<<endl;
if(!strcmp(s, a[j].s2)) cout<<a[j].s1<<endl;
}
}
return 0;
}
八,字符串排序
P1059 - 字符串排序 - New Online Judge (ecustacm.cn)
1,已知小写字母比对应大写ASCII值多32
2,首先是输入问题,string s[1010]; cin>>s[i]; 表示输入一个字符串
那么转换大小写时,s[i][j]表示单个字母,而输出时s[i]表示整个字符串
#include<iostream>
#include<algorithm> //sort()
using namespace std;
int main()
{
string s[1010];
int n;
cin>>n;
for(int i = 0; i < n; ++i)
cin>>s[i];
for(int i = 0; i < n; ++i)
for(int j = 0; j < 10; ++j) {
if(s[i][j] >= 'a' && s[i][j] <= 'z')
s[i][j] -= 32;
else if(s[i][j] >= 'A' && s[i][j] <= 'Z')
s[i][j] += 32;
}
sort(s, s + n);
for(int i = 0; i < n; ++i) cout<<s[i]<<endl;
return 0;
}
九,同构数
P1060 - 同构数 - New Online Judge (ecustacm.cn)
1,考虑到10^5的平方,用long long稳一点
2,第一次敲完,测试样例,输出少了25和625,然后我把judge()判断同构数的函数,粘贴到新建代码里测试了一下:
#include<iostream>
#include<cmath> //pow()
using namespace std;
int judge(long long x)
{
long long sq = pow(x, 2);
cout<<x<<"(x)"<<" ";
cout<<sq<<"(sq)"<<" ";
while(x) {
if(x % 10 != sq % 10)
return false;
x /= 10;
cout<<x<<"(x)"<<" ";
sq /= 10;
cout<<sq<<"(sq)"<<" ";
}
return true;
}
int main()
{
int n;
while(cin>>n) {
if(judge(n)) cout<<n<<endl;
else cout<<"no match"<<endl;
}
return 0;
}
5
5(x) 24(sq) no match
5的平方 = 24???难怪,接着百度,发现pow(5, 2) = 24.999999....所以int把它变成了24.....
可以改成 long long sq = x * x; 或者double sq = pow(5, 2),就没那么多破事
经验:一开始就应该写多个程序测试下,1分钟的事,浪费了半小时观察,观察半天也没发现问题
Ac代码
#include<iostream>
#include<cmath> //pow()
using namespace std;
int judge(long long x)
{
long long sq = x * x;
while(x) {
if(x % 10 != sq % 10)
return false;
x /= 10;
sq /= 10;
}
return true;
}
int main()
{
long long square, n;
cin>>n;
for(int i = 1; i <= n; ++i)
if(judge(i)) cout<<i<<" ";
return 0;
}
100000
1 5 6 25 76 376 625 9376 90625
十,素数回文数的个数
P1061 - 素数回文数的个数 - New Online Judge (ecustacm.cn)
考虑写两个函数,一个判断素数prime(),一个判断回文repeat()
第一次,测试样例输出了2,于是,我用3分钟分别单独拿出两个函数测试,解决了
新技巧:重新写个程序测试函数
#include<iostream>
using namespace std;
int prime(int x) //判断素数
{
if(x == 2) return true;
for(int i = 2; i * i <= x; ++i)
if(x % i == 0)
return false;
return true;
}
int repeat(int x)
{
int y = x, z = 0;
while(y) {
z *= 10;
z += y % 10;
y /= 10;
}
if(z == x) return true;
else return false;
}
int main()
{
int m, n, ans = 0;
cin>>m>>n;
for(int i = m; i <= n; ++i)
if(prime(i) && repeat(i))
ans++;
cout<<ans;
return 0;
}
总结
1,出现bug或者输出错误答案时,不妨花2~3分钟写个新的程序进行测试,花费时间少不说,效率还高
2,字符串相关函数掌握不熟练,比如strcmp, strcpy, strlen, memset, memcpy
3,常犯错误:ans放在循环外,导致不断累积/累加,最终只有第一组输出正确
4,遇到禁止结尾输出空格的题,可用数组保存答案,最后一个答案时,if判断不输出空格
5,注意数组超限或者范围不对,比如矩阵顺逆时针旋转90°
6,草稿纸上梳理思路是个好习惯