题解 P3880 【[JLOI2008]提示问题】

· · 题解

题解 P3880 【[JLOI2008]提示问题】

题目传送门

在博客中食用更佳

大 膜 你!

这题,没什么好说的,就是模拟。

我们考虑,把每一个提示都单独放在一个模块,一个一个处理就好了。

提示1

简单的将所有字母换成'.'即可

题目说简单,貌似也挺简单的,扫一遍字符串,把字母换成'.'就好惹。

另外,这个模块反正要扫一遍字符串,可以做个辅助,统计一下字母的个数。

code:

void hint1()
{
    sum=0;
    for(int i=0;i<len;++i)//遍历字符串
        if (str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z') ++sum,printf(".");//如果找到字母,统计字母数并把字母换成.输出
        else printf("%c",str[i]);//如果是普通的符号,就直接输出
    puts("");//别忘了末尾换行
    return;
}

提示2

从第1个提示而来,将所有字母的个数求出,再将总个数除以三,得到的最接近商的自然数N,将第1个提示中的前N个字母显示

这里需要把总字母个数除以三再四舍五入,比较麻烦。

我们已经统计了字母的个数,所以可以手写一个四舍五入 (lz太菜,不会一些奇怪的函数,有会的评论下叭)

这里可以用(int)number强制转换成int,会舍弃小数部分,保留整数部分,类似于 \left[number\right],也就是向上取整,则(int)number+1为向下取整。

四舍五入代码如下:

int calc(double number)
{
    if (number==(int)number) return (int)number;//如果两数相等,说明除出来是个整数
    if (number-(int)number<(int)number+1-number) return (int)number;//如果这个数与向下取整的差小于向上取整的差,则应该向下取整
    else return (int)number+1;//否则(这个数与向上取整的差小于向下取整的差),则应该向上取整
    //怎样,是不是很玄学?(huaji
}

好了,废了那么多笔墨,我们完成了四舍五入。

接下来,就简单了:把字符串扫一遍,取前 \frac{1}{3} 的字母改成'.'就好了。也是像 hint1 一样做一些准备工作,我们可以记录 \frac{1}{3} 的字母在哪个位置。

code:

void hint2()
{
    int mark=calc(1.0*sum/3);//去除四舍五入后的三分之一,注意要*1.0转double
    int total=0;//字母数量
    for(int i=0;i<len;++i)
        if (str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z')
        {
            ++total;
            if (total==mark) pos=i;//记录三分之一中最后一个字母的位置
            if (total<=mark) printf("%c",str[i]);//还没到三分之一且是字母,把原字符输出
            else printf(".");//在三分之一线以后的字母,化为'.'输出
        }
        else printf("%c",str[i]);//是普通字符,则直接输出
    puts("");
    return;
}

提示3

从第2个提示而来,将剩下的元音字母显示。假如没有可显示的元音字母,则从第1个提示而来,即我们将前2/3的字母显示(同样如不能被3整除则取最接近的整数)

这个提示分两步:首先要判断有没有可显示的元音字母,如果没有,就要扫一遍整个字符串,取前\frac{2}{3}的字母输出。

由于hint2calc函数的帮助,实现起来应该也比较容易,就是判断元音字母的if有点长,菜鸡lz甚至单独写了函数……

判断元音字母的函数,应该比较好写(唱跳rap篮球+C+V就好惹):

bool check(char ch)
{
    if (ch=='a' || ch=='e' || ch=='i' || ch=='o' || ch=='u' || ch=='A' || ch=='E' || ch=='I' || ch=='O' || ch=='U') return 1;//没啥好说的,判断就完事了
    return 0;
}

扫一遍,也没什么难度,写完,这题就差不多了。

void hint3()
{
    bool flag=0;//是否有元音字母
    for(int i=pos+1;i<len;++i)//从上次的三分之一线后开始扫
        if (check(str[i])) {flag=1;break;}//扫到了元音字母就记录
    if (flag)//元音字母
    {
        for(int i=0;i<=pos;++i) printf("%c",str[i]);//先把三分之一线以前的字符输出
        for(int i=pos+1;i<len;++i)//找三分之一线之后的元音字母
            if (str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z')//字母
            {
                if (check(str[i])) printf("%c",str[i]);//元音字母正常输出
                else printf(".");//辅音字母换成.输出
            }
            else printf("%c",str[i]);//普通字符直接输出
    }
    else//没有可输出的元音字母
    {
        int mx=calc(2.0*sum/3);//找到三分之二线
        int total=0;
        for(int i=0;i<len;++i)
        for(int i=0;i<len;++i)
            if (str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z')
            {
                ++total;//统计字母的个数
                if (total<=mx) printf("%c",str[i]);//小于三分之二线直接输出
                else printf(".");
            }
            else printf("%c",str[i]);//超过了三分之二线则化成'.'输出
    }
    puts("");
    return;
}

完成!

完整程序:

#include<bits/stdc++.h>
#define MAXN 60
using namespace std;
char str[MAXN];//字符串
int len,sum,pos;
int calc(double number)
{
    if (number==(int)number) return (int)number;
    if (number-(int)number<(int)number+1-number) return (int)number;
    else return (int)number+1;
}
bool check(char ch)
{
    if (ch=='a' || ch=='e' || ch=='i' || ch=='o' || ch=='u' || ch=='A' || ch=='E' || ch=='I' || ch=='O' || ch=='U') return 1;
    return 0;
}
void hint1()
{
    sum=0;
    for(int i=0;i<len;++i)
        if (str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z') ++sum,printf(".");
        else printf("%c",str[i]);
    puts("");
    return;
}
void hint2()
{
    int mark=calc(1.0*sum/3);
    int total=0;
    for(int i=0;i<len;++i)
        if (str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z')
        {
            ++total;
            if (total==mark) pos=i;
            if (total<=mark) printf("%c",str[i]);
            else printf(".");
        }
        else printf("%c",str[i]);
    puts("");
    return;
}
void hint3()
{
    bool flag=0;
    for(int i=pos+1;i<len;++i)
        if (check(str[i])) {flag=1;break;}
    if (flag)
    {
        for(int i=0;i<=pos;++i) printf("%c",str[i]);
        for(int i=pos+1;i<len;++i)
            if (str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z')
            {
                if (check(str[i])) printf("%c",str[i]);
                else printf(".");
            }
            else printf("%c",str[i]);
    }
    else
    {
        int mx=calc(2.0*sum/3);
        int total=0;
        for(int i=0;i<len;++i)
            if (str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z')
            {
                ++total;
                if (total<=mx) printf("%c",str[i]);
                else printf(".");
            }
            else printf("%c",str[i]);
    }
    puts("");
    return;
}
int main()
{
    cin.getline(str,MAXN);//有空格不能用cin或scanf,要用getline或gets
    len=strlen(str);//字符串长度
    hint1();
    hint2();
    hint3();
    return 0;
}

总结一下本题坑点:

1.输入有空格,cin和scanf很难用,最好用能读一行的来输入

2.四舍五入很麻烦

3.有元音字母不需要输出\frac{2}{3}的字母

4.元音字母的判断