太久不敲代码了,恢复下手感……
洛谷 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);//输出
}