FZU ICPC 2020 寒假训练 3

P1308 统计单词数

题目描述

一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数。现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置。注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章中的某一独立单词在不区分大小写的情况下完全相同(参见样例1 ),如果给定单词仅是文章中某一单词的一部分则不算匹配(参见样例2 )。

输入格式

共2行。第1行为一个字符串,其中只含字母,表示给定单词;第2行为一个字符串,其中只可能包含字母和空格,表示给定的文章。

输出格式

一行,如果在文章中找到给定单词则输出两个整数,两个整数之间用一个空格隔开,分别是单词在文章中出现的次数和第一次出现的位置(即在文章中第一次出现时,单词首字母在文章中的位置,位置从0开始);如果单词在文章中没有出现,则直接输出一个整数−1。

输入 #1

To
to be or not to be is a question

输出 #1

2 0

输入 #2

to
Did the Ottoman Empire lose its power at that time

输出 #2

-1

Accepted

#include <stdio.h>
#include <math.h>
#include <string.h>
int main(){
    int position=0,word_position=0,word=1,word_chance=0,i,j,k;
    char str1[1005];
    char str2[1000005];
    gets(str1);
    gets(str2);
    strcat(str1," ");
    strcat(str2," ");//减少配对难度。
    for(i=0;str1[i]!='\0';i++)
        if(str1[i]>='a') str1[i]-='a'-'A';
    for(i=0;str2[i]!='\0';i++)
        if(str2[i]>='a') str2[i]-='a'-'A'; //将字母全部改为大写;
    for(i=0;str2[i]!='\0';i++){
        if(str2[i]==' ') {
            word=1;
            for(j=position,k=0;j<=i&&str1[k]!='\0';j++,k++){
                if(str1[k]==str2[j]) word*=1;
                else word*=0;
            }
            if(word==1) word_chance++; //如果每次都对就增加符合的次数
            if(word==1&&word_chance==1) word_position=position; //记录第一次符合的位数
            position=i;
            position++;
        }
    }
    if(word_chance==0)printf("-1\n");
    if(word_chance>=1)printf("%d %d\n",word_chance,word_position);
    return 0;
}

gets和scanf的区别

P1553 数字反转(升级版)

题目描述

给定一个数,请将该数各个位上数字反转得到一个新数。
这次与NOIp2011普及组第一题不同的是:这个数可以是小数,分数,百分数,整数。整数反转是将所有数位对调;小数反转是把整数部分的数反转,再将小数部分的数反转,不交换整数部分与小数部分;分数反转是把分母的数反转,再把分子的数反转,不交换分子与分母;百分数的分子一定是整数,百分数只改变数字部分。整数新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零;小数新数的末尾不为0(除非小数部分除了0没有别的数,那么只保留1个0);分数不约分,分子和分母都不是小数(约分滴童鞋抱歉了,不能过哦。输入数据保证分母不为0),本次没有负数。

输入格式

一个数s

输出格式

一个数,即s的反转数

输入 #1

5087462

输出 #1

2647805

输入 #2

600.084

输出 #2

6.48

输入 #3

700/27

输出 #3

7/72

输入 #4

8670%

输出 #4

768%

这题考察的种类多,且需要注意的点细,所以提交代码的时候总是有几组数据没过去(转自洛谷):

  • 关于整数
    • 后面的0不要
    • 遇到“0”或“000000000000”只输出0
  • 关于小数
    • 小数点前的整数:后面的0不要
    • 小数点后的整数:前面的0不要
    • 遇到“0”或“000000000000”只输出0
    • 小数点的正确输出
  • 关于分数
    • 分数前的整数:后面的0不要
    • 分数后的整数:后面的0不要
    • 遇到“0”或“000000000000”只输出0
    • 分数的正确输出
  • 关于百分数
    • 百分数前的整数:后面的0不要
    • 遇到“0”或“000000000000”只输出0
    • 百分号的正确输出

Accepted

#include <stdio.h>
#include <math.h>
#include <string.h>
int main(){
    char str[100000];
    int flag=0;
    int i,j = 0,k;
    int flag1=0,flag2=0,flag3=0;
    int t1=0,t2=0,t3=0;
    scanf("%s",str);
    int len=(int)strlen(str);
    for(i=0;i<len;i++){
        if(str[i]!='0') t3=1;
        if(str[i]=='.'||str[i]=='%'||str[i]=='/') {
            flag=1;
            j=i;
            for(k=0;k<j;k++){
                if(str[k]!='0') t2=1;
            }
        }
        if(i>j&&flag==1&&str[i]!='0'&&flag3==0) {t1=i;flag3=1;}
    }
    
    if(flag==0) {
        if(t3==0) printf("0");
        for(i=len-1;i>=0;i--){
            if(t3!=0&&str[i]!='0'&&flag==0){
                printf("%c",str[i]);
                flag=1;
            }
            else if(t3!=0&&flag==1) printf("%c",str[i]);
        }
    }
    else if(flag==1){
        if(j!=len-1){
    for(k=j-1;k>=0;k--){
        if(t2!=0&&str[k]!='0'&&flag1==0){
            printf("%c",str[k]);
            flag1=1;}
        else if(t2!=0&&flag1==1&&k<j) printf("%c",str[k]);}
        if(t2==0)  printf("0");
        printf("%c",str[j]);
            if(t1!=0){for(k=i-1;k>=t1;k--)
    {
        if(flag2==0&&str[k]!='0'){
       printf("%c",str[k]);
       flag2=1;}
        else if(flag2==1) printf("%c",str[k]);
    }}
            if(t1==0) printf("0");
        }
    else{
         if(t2==0) printf("0");
        for(k=j-1;k>=0;k--){
          
           if(t2!=0&&str[k]!='0'&&flag1==0){
               printf("%c",str[k]);
               flag1=1;}
           else if(t2!=0&&flag1==1&&k<j) printf("%c",str[k]);}
        printf("%c",str[j]);
        
    }
    }
    return 0;
}

另解(转自:洛谷题解):

//【P1553】数字反转(升级版) - 洛谷 - 100
#include <string>
#include <iostream>
#include <algorithm>

// 自己写的反转函数,返回反转并去掉前导零之后的字符串
std::string reverse(std::string s) {
    int zeroCount = 0;
    std::reverse(s.begin(), s.end()); // 反转
    // 范围 for 循环,用于统计前导零个数
    for (auto i : s)
        if (i == 48) ++zeroCount;
        else break;
    s.erase(s.begin(), s.begin() + zeroCount);
    return (s != "" ? s : "0"); // 特判
}

// 用于去掉后导零
std::string deleteTail(std::string s) { 
    int zeroCount = 0;
    for (int i = s.size() - 1; i >= 0; --i)
        if (s[i] == 48) ++zeroCount;
        else break;
    s.erase(s.end() - zeroCount, s.end());
    return (s != "" ? s : "0");
}

int main() {
    std::string s;
    std::cin >> s;
    if (s.back() == '%') {
        std::cout << reverse(s.substr(0, s.size() - 1)) << "%" << std::endl;
        return 0;
    }
    for (auto i : s) {
        std::string left, right;
        // 其实还有一种不需要遍历字符串的做法,直接 find() 即可,但是当时没想到
        if (i == '/') {
            left = s.substr(0, s.find("/"));
            right = s.substr(s.find("/") + 1);
            std::cout << reverse(left) << "/" << reverse(right) << std::endl;
            return 0;
        }
        if (i == '.') {
            left = s.substr(0, s.find("."));
            right = s.substr(s.find(".") + 1);
            std::cout << reverse(left) << "." << deleteTail(reverse(right)) << std::endl;
            return 0;
        }
    }
    // 最后剩下的一种情况是正整数
    std::cout << reverse(s) << std::endl;
    return 0;
}

分别解释一下用到的 STL 算法。
std::reverse(),顾名思义,用于反转序列。需要提供首尾迭代器作为参数。
std::string::erase(),传入两个迭代器 l,r,清除[l,r)范围内的字符。
std::string::substr(),用于提取子字符串,用法与前者类似。
std::string::find(),用来查找字串在母串中第一次出现的位置。

P1028 数的计算

题目描述

我们要求找出具有下列性质数的个数(包含输入的自然数n):先输入一个自然数n(n≤1000),然后对此自然数按照如下方法进行处理:不作任何处理;在它的左边加上一个自然数,但该自然数不能超过原数的一半;加上数后,继续按此规则进行处理,直到不能再加自然数为止.

输入格式

1个自然数n(n≤1000)

输出格式

1个整数,表示具有该性质数的个数。

输入 #1

6

输出 #1

6

Accepted

#include <stdio.h>
#include <math.h>
#include <string.h>
int main(){
    int n;
    int a[10000];
    a[0]=1;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        if(i%2) a[i]=a[i-1];
        else a[i]=a[i-1]+a[i/2];
    }
    printf("%d\n",a[n]);
    return 0;
}

n%2==0时, f(n)=f(n-1)+f(n/2);
n%2==1时, f(n)=f(n-1).

P1036 选数

题目描述

已知 n 个整数 x1,x2,…,xn,以及1个整数k(k<n)。从n个整数中任选k个整数相加,可分别得到一系列的和。例如当
n=4,k=3,4个整数分别为3,7,12,19时,可得全部的组合与它们的和为:
3+7+12=22
3+7+19=29
7+12+19=38
3+12+19=34。
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:
3+7+19=29。

输入格式

键盘输入,格式为:n,k(1≤n≤20,k<n)
x1,x2,…,xn(1≤xi≤5000000)

输出格式

屏幕输出,格式为:
1
1个整数(满足条件的种数)。

输入 #1

4 3
3 7 12 19

输出 #1

1

Accepted

使用递归,

#include <stdio.h>
#include <math.h>
#include <string.h>
int a[10000];
int sum=0;
int n,k;
int judge(int n){
    int i;
    if(n==1) return 0;
    else if(n==2) return 1;
    else if(n>2) {
        for (i=2;i<=sqrt(n);i++ ) {
            if(n%i==0) return 0;
        }
        return 1;
    }
    return 0;
}
void choice(int flag[],int p,int k){//标记数组,所在位置,选几个数
    if(k==0){
        int num=0;
        for(int j=0;j<n;j++){
            if(flag[j]==1)
                num+=a[j];
        }
        if(judge(num)) sum++;
    }
    else{
        for(int j=p;j<n;j++){
            if(!flag[j]) flag[j]=1;
            choice(flag,j+1,k-1);
            flag[j]=0;
        }
    }
}
int main(){
    int i;
    int flag[10000]={0};//使用数组flag保存各数字是否被用过的标记
    scanf("%d %d",&n,&k);
    for(i=0;i<n;i++) scanf("%d",&a[i]);
    choice(flag,0,k);
    printf("%d\n",sum);
    return 0;
}

P1149 火柴棒等式

题目描述

给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。用火柴棍拼数字0−9的拼法如图所示:
FZU ICPC 2020 寒假训练 3
注意:
1.加号与等号各自需要两根火柴棍
2.如果A≠B,则A+B=C与B+A=C视为不同的等式(A,B,C>=0)n根火柴棍必须全部用上

输入格式

一个整数n(n<=24)。

输出格式

一个整数,能拼成的不同等式的数目。

输入 #1

14

输出 #1

2

输入 #2

18

输出 #2

9

说明/提示

【输入输出样例1解释】
2个等式为0+1=1和1+0=1。
【输入输出样例2解释】
9个等式为:

0+4=4
0+11=11
1+10=11
2+2=4
2+7=9
4+0=4
7+2=9
10+1=11
11+0=11

Accepted

#include <stdio.h>
#include <math.h>
#include <string.h>

int main(){
    int n,i,j;
    int num=0;
    int number[10]={6,2,5,5,4,5,6,3,7,6};
    int arr[2005]={6};
    scanf("%d",&n);
    for(i=1;i<=2000;i++){//把1-1000表示出来
        j=i;
        while(j>=1){//求i每一个数所需要的火柴棒
            arr[i]=arr[i]+number[j%10];
            j/=10;
        }
    }
    for(i=0;i<=1000;i++){
        for(j=0;j<=1000;j++){
            if(arr[i]+arr[j]+arr[i+j]+4==n) num++;
        }
    }
    printf("%d\n",num);
    
    return 0;
}
上一篇:FZU ICPC 2020 寒假阶段测试 2


下一篇:FZU ICPC 2020 寒假训练 1