日练 23.8.1

太久不敲代码了,恢复下手感……

洛谷 P5587 打字练习

题目描述

R 君在练习打字。

有这样一个打字练习网站,给定一个范文和输入框,会根据你的输入计算准确率和打字速度。可以输入的字符有小写字母、空格和 .(英文句号),输入字符后,光标也会跟着移动。

输入的文本有多行,R 君可以通过换行键来换行,换行后光标移动到下一行的开头。

R 君也可以按退格键(为了方便,退格键用 < 表示),以删除上一个打的字符,并将光标回移一格。特殊的,如果此时光标已经在一行的开头,则不能继续退格(即忽略此时输入的退格键)。

网站的比较方式遵循以下两个原则:

  • 逐行比较,即对于范文和输入的每一行依次比较,不同行之间不会产生影响,多余的行会被忽略。
  • 逐位比较,即对于两行的每一个字符依次比较,当且仅当字符相同时才会被算作一次正确,否则会被算作错误。计算答案时,只统计相同的字符个数。

需要注意的是,回车键不会被计入正确的字符个数。

R 君看到网站上显示他花了 �T 秒完成了这次的打字游戏,请你计算出他的 KPM(Keys per minutes,每分钟输入的字符个数),答案四舍五入保留整数部分。

输入格式

R 君会依次告诉你网站的范文,他的输入和花费的时间。

其中范文和输入将会这样读入:给定若干行字符串,以单独的一行 EOF 结束,其中 EOF 不算入输入的文本。

最后一行一个整数 �T,表示他打字花费了 �T 秒。

可以参考样例输入输出文件和样例解释辅助理解。

输出格式

一行一个整数,表示 KPM。

输入输出样例

输入 #1

hello world.
aaabbbb
x
EOF
heelo world.
aaacbbbb
y<x
EOF
60

输出 #1

18

说明/提示

样例解释

第一行的正确字符数为 11。
第二行的正确字符数为 6,错误的字符 c 仍会占据一个位置。
第三行的正确字符数为 1,R 君使用退格键删除了被打错的字符 y

数据范围

对于20%的数据,不存在换行键。
对于40%的数据,不存在退格键。
对于100%的数据,T≤10^3,保证每个文本段的总字符数(包括换行)不超过10^5个且总行数不超过10^4。

解答过程

按最开始的想法嘞,就是整行读入,然后逐个判断是否需要退格并写入字符数组,最后进行比较,想法简单,实践也挺简单,就是参数设的多了点……

#include<bits/stdc++.h>
using namespace std;

const int N=1e6;
long long i,j,len,top,t,l[N],score,number,r,tim;
double kpm;
char a[N],b[N];
string s;

int main(){
    getline(cin,s);  //读入原文
    while(s!="EOF"){
        len=s.size();  //该行字符串长度
        t++;  //累计行数
        j=top;  //字符数组下标起点
        for(i=top;i<len+top;i++){  //遍历字符串
            if(s[i-top]=='<'){
                if(j-top>0)j--;  //只有该行还能够减去时‘<’字符起作用
			}
            else{
                a[j]=s[i-top];
                j++;  //将字符串写入数组,下标加一
            }
        }
        l[t]=j-top;  //储存该行字符数
        number+=l[t];  //总字符数
        top=j;  //下一段的起点
        getline(cin,s);
    }
    t=0;
    top=0;
    
    getline(cin,s);  //读入打字,与上一段基本相同
    while(s!="EOF"){
        len=s.size();
        j=top;
        t++;
        for(i=top;i<len+top;i++){
            if(s[i-top]=='<'){
                if(j-top>0)j--;
			}
            else{
                b[j]=s[i-top];
                j++;
            }
        }
        if(j-top>l[t])top+=l[t];  //比原文多出的字符不要
        else top=j;
        getline(cin,s);
    }
    
    for(i=0;i<number;i++){
        if(a[i]==b[i])r++;
    }
    cin>>tim;
    kpm=r*60.0/tim*1.0+0.5;  //+0.5解决四舍五入
    cout<<(int)kpm<<endl;
    return 0;
}

二十分钟写了一下,样例过了,提交后不出意外的WA了8个点……原因是题目数据要求中的换行考虑不充分,只考虑到第二段比原文字数超出的情况,没考虑到少的情况 (写的时候觉得不会少,结果调了半个多小时才发现)

只要把上面读入第二段时循环末尾对参数top的赋值直接改成下面就可以AC了……

top+=l[t];

后面一想,我废这么大劲把二维的字符段存成一维的字符数组再去判断,中间转换所设的参数非常繁琐,为什么不直接跳过中间的步骤呢?于是,很快啊,修改了一下我的代码%%%

#include<bits/stdc++.h>
using namespace std;

const int N=1e6;
long long i,j,len,t,l[N],r,tim;
double kpm;
string a[N],b[N];

int main(){
    getline(cin,a[t]);
    while(a[t]!="EOF"){
        len=a[t].size();
        j=0;
        for(i=0;i<len;i++){  //遍历该字符串
            if(a[t][i]=='<'){
                if(j>0)j--;  //判断能减时下标减一
			}
            else{
                a[t][j]=a[t][i];  //覆盖
                j++;
            }
        }
        l[t]=j;
        t++;
        getline(cin,a[t]);
    }
    t=0;
    
    getline(cin,b[t]);
    while(b[t]!="EOF"){
        len=b[t].size();
        j=0;
        for(i=0;i<len;i++){
            if(b[t][i]=='<'){
                if(j>0)j--;
			}
            else{
                b[t][j]=b[t][i];
                j++;
            }
        }
        for(i=0;i<min(l[t],j);i++){  //按行比较两段相同字符数
            if(a[t][i]==b[t][i])r++;
        }
        t++;
        getline(cin,b[t]);
    }
    
    cin>>tim;
    kpm=r*60.0/tim*1.0+0.5;
    cout<<(int)kpm<<endl;
    return 0;
}

这里还是要注意比较的时候要取两段字符串的最小值,第一次交没注意WA了一大半……在看题解时发现大佬使用pop_back()和push_back()函数直接秒杀……orz 很多时候函数可以很轻松的实现一些功能,可以省去很多设参数写公式,这波是练得少公式不熟写的太慢,还得多练(′•灬•‘)

#include<bits/stdc++.h>
using namespace std;

const int N=1e6;
long long n,m,cnt;
string s[N],t[N],s1;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(getline(cin,s1),s1!="EOF"){
        n++;
		for(char i:s1)
            if(i=='<')
                if(!s[n].empty())
                    s[n].pop_back();  //模拟,如果是退格且string中还有字符就删掉一个
		    else s[n].push_back(i);  //否则加上去
	}
	while(getline(cin,s1),s1!="EOF"){
		if(++m>n) break;
		for(char i:s1)
            if(i=='<')
                if(!t[m].empty())
                    t[m].pop_back();
		    else t[m].push_back(i);  //同上
		for(int i=0;i<min(t[m].size(),s[m].size());i++)
            cnt+=s[m][i]==t[m][i];  //逐位比较
	}
	cin>>m;
	cout<<(long long)(cnt*60.0/m+0.5);//输出
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值