🌼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,草稿纸上梳理思路是个好习惯



















