【洛谷新手村解题报告三 字符串/递归前】C++语言,一题多解,思路和WA反思

【洛谷新手村解题报告三】

  • 简单字符串
  • 过程函数与递归

首先下一部分!字符串,这个前面两题新手跳过吧

简单字符串

第三题 统计单词数 [2/2]

给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置。
注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章中的某一独立单词在不区分大小写的情况下完全相同,如果给定单词仅是文章中某一单词的一部分则不算匹配。
输入
To
to be or not to be is a question
输出
2 0
输入
to
Did the Ottoman Empire lose its power at that time
输出
-1

有点麻烦的题目。首先把给定字母都变成小写,利用函数tolower()
然后把文章搞进来,for循环遍历
如果遇到空格,continue;
如果遇到字母,记录字母的头位置和尾位置,如果这个长度和目标字符串不同那也继续
如果长度相同,判断每一个字母tolower()之后与给定字符串比较即可

char aim[15];				//给定字符串
char now[1000550];			//文章字符串

int main(){
    scanf("%s",aim);
    getchar();
    for(int i=0;i<strlen(aim);++i)		//转换成小写
        aim[i]=tolower(aim[i]);
    int ansp=-1,cnt=0;			//ansp记录第一次出现位置 cnt记录出现次数
    gets(now);
    int len=strlen(now);
    for(int i=0;i<len;++i){
        if(now[i]==' ')continue;				//空格继续
        int st=i,ed=i;							//记录头尾位置
        while(ed<len && now[++ed]!=' ');
        ed--;									//回退一下末位置
        if(ed-st==strlen(aim)-1){				//注意-1
            for(int j=st;j<=ed;j++){			//每位都遍历
                now[j]=tolower(now[j]);			//别忘了转换成小写字母
                if(aim[j-st]!=now[j])break;		//不相同直接退出吧
                if(j==ed){						//判断完了,吻合
                    if(ansp==-1)ansp=st;
                    cnt++;
                }
            }
        }
        i=ed;
    }
    if(ansp==-1)printf("-1");					//没出现过
    else printf("%d %d",cnt,ansp);
    return 0;
 }

第四题 数字反转(升级版) [2/2]

整数反转是将所有数位对调。
小数反转是把整数部分的数反转,再将小数部分的数反转,不交换整数部分与小数部分。
分数反转是把分母的数反转,再把分子的数反转,不交换分子与分母。
百分数的分子一定是整数,百分数只改变数字部分。

又是反转!不过限制条件多了点。
我们使用 string str; 来操作
输入的时候判断有没有读到% . /的符号,判断是哪种类型
然后字符串反转利用reverse()函数 报告二里面也有提到一下
然后删除前导0的话,我们使用Str.substr() 函数
while(aa.size()>1 && aa[0]=='0')aa=aa.substr(1);·
这样可以删除多余的前导0 也可以防止把0删没了。。

注意:小数的小数点部分删除的是后导0
方法:reverse 一下 删除前导0 再reverse 回去!

代码部分,这个太模拟了就不贴了,如果想看可以去我的洛谷ID YanLei
当然作弊AC是不太好的,仅供参考吧

第五题 垂直柱状图 [1/1]
题意:记录每个字母出现的次数,做成柱状图

这个重点考虑怎么输出柱状图的问题,一共要输出多少行*?
那就是所有字母出现的次数最多的那个次数MA就行了
然后第i 行 判断字母j 出现的次数有没有大于等于 MA-i 有就输出 *

核心代码:

for(int i=0;i<26;++i)MA=max(MA,cnt[i]);
    for(int i=0;i<MA;++i){
        for(int j=0;j<26;++j){
            if(cnt[j]>=MA-i)putchar('*');
            else putchar(' ');
            if(j!=25)putchar(' ');
        }
        puts("");
    }

第六题 小书童——密码 [1/1]
题意:每个字母后移n位
a 后移1位是b z后移1位是a
想法: 后移n位就是后移 n%26 位,后移27和后移1位一样嘛 化简一下
然后算出每个字母- ‘a’ 是多少,加上后移的 n 最后再 %26 在加上 ‘a’
呃呃,有点晕 理一下
每个字母- ‘a’ 表示距离字母’a’ 的间隔 ‘c’-‘a’=2
间隔加n 表示字母在’a’ 后面n个
因为超过’z’ 之后会回到’a’ 那么我们令结果%26 就是最终间隔
间隔加上’a’ 就是字母了

char ch=(aa[i]-'a'+n)%26+'a';

过程函数与递归

这关开始就难打了,奥利给!

第一题 数的计算 [3/3]

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

自己写一个 int sol(int lef) 表示最左边的数字是lef的时候的个数
边界条件: sol(1)=1;
然后 lef 的左边可以添加的数字有 1,2 …… ,lef/2
然后他们的和就是sol(lef)的值

第一次代码:

ll sol(int lef){
    if(lef==1)return 1;
    ll ans=1;
    for(int i=1;i<=lef/2;++i){
        ans+=sol(i);
    }
    return =ans;
}

不交不知道,一交吓一跳吧!满屏TLE,感动的不知道怎么样了
好吧,我们需要记忆递归 如果算出sol(5)的值了,那以后递归调用就不需要再算一遍了!不然的话原来的复杂度就是高次增长了

记忆化递归

ll cnt[MAX];
ll sol(int lef){
    if(lef==1)return 1;
    if(cnt[lef])return cnt[lef];
    ll ans=1;
    for(int i=1;i<=lef/2;++i){
        ans+=sol(i);
    }
    return cnt[lef]=ans;
}

成功AC!这才第一题

第二题 选数 [3/3]

已知 n 个整数 x1,x2,…,xn以及1个整数k(k 从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最大20

Sol 1状态压缩
因为每个数字都是选与不选的关系,
利用二进制从i= 0 到 1< 比如5 表示二进制为 000101 表示选择数字第一个和第三个
然后判断这个 i是不是有k个1,再判断这几个位置和是不是素数
写起来也还可以但是不是递归,跳过 有兴趣可以百度一下
复杂度O(2n)

Sol 2 递归
typedef long long ll; //写起来方便写
我们写一个递归函数 ll sol(int p,int choo,ll num)
表示选择到第p个位置,选了choo个数字,选择的数字和是num
边界1:如果p== n && choo 表示你都处理完最后一个数字了还没选k个,无解
边界2:如果choo==k
选好k个数字了,判断num 是否是质数,是 返回1解 否无解
边界3 优化:如果n-p+choo 表示你剩下的数字全选都不够k个了,那直接返回无解吧
处理:每个数字都有选和不选两种情况
返回 sol(p+1,choo,num)+sol(p+1,choo+1,num+aa[p+1]);

最后sol(0,0,0ll)就是答案啦

ll aa[MAX];
int n,k;
bool pd(ll nn){
    if(nn==2)return 1;
    for(int i=2;i*i<=nn;++i){
        if(nn%i==0)return 0;
    }
    return 1;
}
ll sol(int p,int choo,ll num){
    if(p==n && choo<k)return 0ll;
    if(choo==k){
        show(num);
        if(pd(num))return 1ll;
        else return 0ll;
    }
    if(n-p+choo<k)return 0ll;
    return sol(p+1,choo,num)+sol(p+1,choo+1,num+aa[p+1]);
}

好啦,有点长了,这么详细这么亲民不给个评论 吗?
有错欢迎指出www

你可能感兴趣的:(【洛谷新手村解题报告三 字符串/递归前】C++语言,一题多解,思路和WA反思)