玩命加载中 . . .

洛谷官方提单——字符串入门题解(部分水题警告)


今天是字符串的入门题,字符串的题学习建议使用cpp的stl中的string,虽然STL又名sometime time limit,但是自己使用char数组写轮子很容易产生越界导致的RTE或者SE。
同时希望大家能够记住string.h和string的函数,至少看名字要知道他是什么意思,这样才能极大的提高做串类型的题的速度。
废话不多说,直接进入正题。

题目0:自动修正

简单的大小写替换题。代码给两种

//python
//print(input().upper())

//cpp头文件啥的省略嗷
for(int i =0;i<len;i++){
    if(s[i]>='a'&&s[i]<='z') printf("%c",s[i]-'a'+'A');
    else printf("%c",s[i]);
}

题目1:小书童——密码

简单的对每一个字母+n即可,但是注意整个要对26取模保证始终是字母。

for(int i = 0; s[i]<len ; i++) 
    printf("%c",(s[i]-'a'+n)%26+'a')

题目2:笨小猴

实不相瞒,这道题我坐着我觉得我也蛮笨的(bushi),坑点在于:

  1. 你的min如果不对book数组中的0进行特别判定的话,那么你会WA;
  2. 一般素数是不会判断0的(没错,我一开始的接口没有判断0),所以我在0卡了好一会儿。
    代码如下
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    char memo[105];
    int book[26];
    int max(int a, int b) { return a > b ? a : b; }
    int min(int a, int b) { return a < b ? a : b; }
    bool Is_Prime(int num) {
     if (num == 0) return false;
     if (num == 1) return false;
     if (num == 2) return true;
     int bound = sqrt(num);
     for (int i = 2; i <= bound + 1; i++) {
         if (num % i == 0)
             return false;
     }
     return true;
    }
    int main() {
     int mmax = -1, mmin = 999;
     scanf("%s", memo);
     int len = strlen(memo);
     for (int i = 0; i < len; i++) book[memo[i] - 'a']++;
     for (int i = 0; i < 26; i++) {
         mmax = max(mmax, book[i]);
         if (book[i] == 0)  continue;
         else mmin = min(mmin, book[i]);
     }
     if (Is_Prime(mmax - mmin)) return 0 * printf("Lucky Word\n%d\n", mmax - mmin);
     else return 0 * printf("No Answer\n0\n");
    }

    题目3:口算计算题

    根据题目进行模拟即可,但是这里有个重点是如何区分三个还是两个的情况(所以这题的难度真的是普及-吗?)。
    具体实现方式见代码和注释。
    #include<string>
    #include<iostream>
    #include<stdio.h>
    using namespace std;
    int Num_lenth(int num){
     int len = 0;
     if (num < 0 || num == 0) len++;
     while (num) len++, num /= 10;
     return len;
    }
    int To_num(string s){
     int ans = 0, len = s.size();
     for (int i = 0; i < len; i++) ans = ans * 10 + s[i] - '0';
     return ans;
    }
    int main(){
     string sa, sb;
     int a, b, n;
     char ch, copy;
     cin >> n;
     for (int i = 1; i <= n; i++){
         cin >> ch >> sa >> sb; 
         if (ch >= '0' && ch <= '9') sa = ch + sa, ch = copy;//因为第一个不是字母,所以我们把copy赋予ch方便后续判断
         //string类加法就是拼接字符串,copy是上一轮的字符。
         a = To_num(sa), b = To_num(sb);  
         //本来打算用atoi但是因为是string就得手造轮子
         int a_len = Num_lenth(a), b_len = Num_lenth(b);
         if (ch == 'a') printf("%d+%d=%d\n%d", a, b, a + b, a_len + b_len + 2 + Num_lenth(a + b)), copy = ch;
         else if (ch == 'b') printf("%d-%d=%d\n%d", a, b, a - b, a_len + b_len + 2 + Num_lenth(a - b)), copy = ch;
         else if (ch == 'c') printf("%d*%d=%d\n%d", a, b, a * b, a_len + b_len + 2 + Num_lenth(a * b)), copy = ch;
         if (i < n) cout << endl;
         //这里注意,多输出换行爆0
     }
     return 0;
    }

    题目4:标题统计

    假如你是顺序做题的话,经历了上面的题的洗礼,这道题简直就是送分题,但是,这里科普一下:gets函数请勿在比赛的时候使用(C11以上已经不允许使用了)。
    #include<stdio.h>
    #include<string.h>
    int main(){
     char s[10];
     int ans = 0, len;
     fgets(s, 10, stdin);
     len = strlen(s);
     for (int i = 0; i < len; i++) {                  
         if (s[i] >= 'A' && s[i] <= 'Z') ans++;
         if (s[i] >= 'a' && s[i] <= 'z') ans++;
         if (s[i] >= '0' && s[i] <= '9') ans++;
     }
     return 0 * printf("%d\n", ans);
    }

    题目5:文字处理软件

    按照题目使用库函数即可(自己写费时费力)
    #include<cstdio>
    #include<cstring>
    const int MAXN = 105;
    char text[MAXN], temp[MAXN];
    int main(){
     int n, op, a, b;
     scanf("%d\n%s", &n, text);
     for (int i = 1; i <= n; i++) {
         scanf("%d", &op);
         if (op == 1) {
             scanf("%s", temp);
             strcat(text, temp);
             printf("%s\n", text);
         }
         else if (op == 2) {
             scanf("%d %d", &a, &b);
             text[a + b] = '\0';
             strcpy(temp, text + a);
             strcpy(text, temp);
             printf("%s\n", text);
         }
         else if (op == 3) {
             scanf("%d %s", &a, temp);
             strcat(temp, text + a);
             text[a] = '\0';
             strcat(text, temp);
             printf("%s\n", text);
         }
         else {
             scanf("%s", temp);
             char* ans = strstr(text, temp);
             if (ans != NULL) printf("%d\n", int(ans - text));
             else printf("-1\n");
         }
     }
     return 0;
    }

    题目6:统计单词数

    按照题目要求,请勿使用cin因为cin无法读入空格,这里提供另外一个思路,循环到文件结尾,将文章的每个单词读入string中,然后处理都为大写或者小写,直接strcmp每个string(这里就不写咯)。
    #include<iostream>
    #include<cstring>
    #include<string>
    using namespace std;
    int main(){
     string article, word;
     int pass_len, word_len, t = 0, pos = 0, j;
     getline(cin, word), getline(cin, article);
     word_len = word.size(), pass_len = article.size();
     for (int i = 0; i < word_len; i++) word[i] = toupper(word[i]);
     //不采用-'a'+'A'的方式主要是需要多写一个判断其是不是属于'a'到'z'之间
     for (int i = 0; i < pass_len; i++) article[i] = toupper(article[i]);
     for (int i = 0; i <= pass_len - word_len; i++){
         for (j = 0; j < word_len; ++j){
             if (article[j + i] != word[j]) break;
             if (i > 0 && article[i - 1] != ' ') break;
         }
         if (j == word_len && (article[j + i] == ' ' || j + i == pass_len)) 
             if (++t == 1) pos = i;
     }
     if (t == 0) cout << -1;
     else cout << t << " " << pos;
     return 0;
    }

    题目7:手机

    由于每个字母需要按的次数是固定的,所以我们打表即可。
    #include<iostream>
    #include<cstdio>
    #include<string>
    using namespace std;
    int cnt[26] = { 1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,1,2,3,1,2,3,4 };
    int main(){
     string s;
     getline(cin, s);
     int ans = 0, len = s.length();
     for (int i = 0; i < s.length(); i++){
         if (s[i] >= 'a' && s[i] <= 'z') ans += cnt[s[i] - 'a'];
         if (s[i] == ' ') ans++;
     }
     return 0* printf("%d", ans);
    }

    题目8:honoka的键盘

    遍历两次,同时使用book数组来保证’VK’没有被使用,且由于只能变换一次保证最多的VK,因此答案必然是VK的数目或者VK+1。
    #include<cstdio>
    using namespace std;
    int n, ans, flag, book[105];
    char s[105];
    int main(){
     scanf("%d%s", &n, s);
     for (int i = 1; i < n; i++)
         if (s[i - 1] == 'V' && s[i] == 'K')
             ans++, book[i - 1] = book[i] = 1;
     for (int i = 1; i < n; i++)
         if (!flag && !book[i - 1] && !book[i] && s[i - 1] == s[i])
             flag = 1, ans++;
     return 0 * printf("%d\n", ans);
    }

    题目9:单词覆盖还原

    题目含义就是,只要b开头,第二个是o或第三个是y或第二三是oy,那么就算一个boy;girl同理
    #include<iostream>
    #include<string>
    using namespace std;
    int main() {
     int bcnt = 0, gcnt = 0;
     string s;
     cin >> s;
     for (int i = 0; i <= s.length(); i++) {
         if (s[i] == 'b' || s[i + 1] == 'o' || s[i + 2] == 'y')bcnt++;
         if (s[i] == 'g' || s[i + 1] == 'i' || s[i + 2] == 'r' || s[i + 3] == 'l') gcnt++;
     }
     cout << bcnt << endl << gcnt << endl;
     return 0;
    }

    题目10:数字反转(升级版)

    前面有一个简易版本的数字反转,这个要难一点,但是依旧只要按照题目所说就可以正确做出来(就是细节特别多),这里使用的是栈。
    没错,细节多到炸,我以为按照题意不会出现1.00100这种数字,结果在这个点疯狂WA,而且还有很多奇形怪状的坑点,调BUG调了40min。
    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<stack>
    using namespace std;
    char memo[30];
    int main() {
     stack<char> s;
     scanf("%s", memo);
     int len = strlen(memo);
     int signal_pos = len, zero_flag = 1;
     for (int i = 0; i < len; i++) if (memo[i] < '0' || memo[i]>'9') signal_pos = i;//非整数
     for (int i = 0; i < signal_pos; i++) s.push(memo[i]);//符号前进栈
     while (s.size() != 0) {//输出
         char temp = s.top();
         if (temp != '0') zero_flag = 0;
         if (zero_flag == 1);
         else cout << temp;
         s.pop();
     }
     if (zero_flag == 1) cout << 0;//说明符号前整个都是0,只有一个0
     cout << memo[signal_pos];//输出符号或整数的最后一位
     zero_flag = 1;
     for (int i = signal_pos + 1; i < len; i++) {
         if (zero_flag == 0) s.push(memo[i]);
         else {
             if (memo[i] == '0') continue;//原来数据的前导0我们不要
             else {
                 zero_flag = 0;//不是前导0了
                 s.push(memo[i]);
             }
         }
     }
     if (s.size() == 0 && signal_pos != len && signal_pos != len - 1) cout << 0;
     //第一个说明小/分数后面是0,第二个说明是整数,第三个说明是百分数
     zero_flag = 1;
     while (s.size() != 0) {//输出
         char temp = s.top();
         if (temp != '0') zero_flag = 0;
         if (zero_flag == 1);
         else cout << temp;
         s.pop();
     }
     return 0;
    }

    题目11:斯诺登的密码

    这题首先,你得打表,不然你就得写很多很多ifelseif;其次,然后对于平方后取模,建议也直接打表,不然前导0去除很恶心。
    //先挖个坑,由于环境不一样,所以你直接copy会CE
    #pragma warning(disable:4996)
    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    char dic[30][10] = { "zero","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty","a","both","another","first","second","third" };
    int ind[30] = { 0,1,4,9,16,25,36,49,64,81,00,21,44,69,96,25,56,89,24,61,0,1,4,1,1,4,9 },ans[10]; 
    char s[100];
    int main(){
     int pos = 0, flag = 0;
     for (int i = 0; i < 6; i++){
         scanf("%s", s);
         for (int j = 0; j < 26; j++){
             if (!strcmp(s, dic[j])){
                 ans[pos++] = ind[j];
                 break;
             }
         }
     }
     sort(ans, ans + pos);
     for (int i = 0; i < pos; i++){
         if (flag) printf("%.2d", ans[i]); 
         else{
             if (ans[i]){
                 printf("%d", ans[i]);
                 flag = 1;
             }
         }
     }
     if (!flag) printf("0");
     return 0;
    }

    题目12:你的飞碟在这里

    按照题目来,此题没有坑点(早期做的题目,代码懒得重写)。
    #include<stdio.h>
    #include<string.h>
    char st[7],gr[7];
    int main(){
     long long int star,group;
     int stl,gro;
     scanf("%s%s",st,gr);
     star=1,group=1,stl=strlen(st),gro=strlen(gr);
     for(int i=0;i<stl;i++) star*=(st[i]-'A'+1);
     star=star%47;
     for(int i=0;i<gro;i++) group*=(gr[i]-'A'+1);
     group=group%47;
     if(star==group) printf("GO");
     else printf("STAY");
     return 0;
    }

    题目13:语句解析

    scanf属于格式输入,使用scanf可以定向输入想要位置的值,然后按照题目要求就可以做了。
    #include<stdio.h>
    int main(){
     int a[3] = { 0,0,0 };
     char s1, s2;
     while (scanf("%c:=%c;", &s1, &s2) == 2)
         if (s2 >= '0' && s2 <= '9') a[s1 - 'a'] = s2 - '0';
         else a[s1 - 'a'] = a[s2 - 'a'];
     return 0 * printf("%d %d %d", a[0], a[1], a[2]);
    }

    题目14:垂直柱状图

    K&R C书籍上的原题,属于比较繁琐的字符串模拟,重点是你要先找到最大的数来决定你要输出的最大范围
    #include<cstdio>
    #include<string>
    #include<iostream>
    using namespace std;
    int book[26];
    int max(int x, int y) { return x > y ? x : y ;}
    int main(){
     int n, maxn = -1;;
     string a;
     for (int i = 0; i < 4; i++){
         getline(cin,a);
         n = a.length();
         for (int j = 0; j < n; j++)
             if (a[j] >= 'A' && a[j] <= 'Z')
                 book[a[j] - 'A']++;
     }
     for (int i = 0; i < 26; i++)
         maxn = max(maxn, book[i]);
     for (int i = maxn; i > 0; i--) {
         for (int j = 0; j < 26; j++) {
             if (book[j] >= i)printf("* ");
             else printf("  ");
         }
         printf("\n");
     }
     for (int i = 0; i < 26; i++) printf("%c ", i + 'A');
     return 0;
    }

今天的字符串入门就是这些啦,内容虽然不难,但题都或多或少的繁琐(考虑多种边界条件),会了基本之后才能为后面更难的字符串题目(字符串的难题基本都得构造出状态机,因此需要很好的基础),一天杀一单子题还是有点刺激。


文章作者: AleXandrite
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 AleXandrite !
  目录