题解:P13499 「Cfz Round 6」Umiyuri Kaiteitan
\(40\) 分做法
由于最终求的是每个文件包含的字符数量,所以并不需要记录每个文件名与顺序,只需要记录文件名的长度之和即可。
我们用 \(ans_i\) 表示文件 \(i\) 包含的字符数量,\(vis_i\) 表示文件 \(i\) 是否被创建,\(cnt\) 表示目前文件名的总长度(包括相邻两个文件名之间的空格)。每当执行一条指令时,先通过 \(vis\) 数组来检测文件是否存在,若不存在则标记 \(vis_i = 1\) 并将 \(cnt\) 加上 \(2\)(文件名长度加上一个空格的长度),更新文件名总长度;然后把 \(ans_i\) 设为 \(cnt\),即文件 \(i\) 在写入后的大小。
注意,上面的计数方法有个小漏洞:\(cnt\) 会在结尾多记录一个空格。解决办法很简单,可以在第一次操作时把 \(cnt\) 减一,或者更新文件大小时把 \(ans_i\) 设为 \(cnt - 1\) 即可。
于是,我们得到代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
int n,m,ans[maxn];
bool vis[maxn];
int main(){
cin>>n>>m;
int a,cnt=0;
for(int i=1;i<=n;++i){
cin>>a;
//文件不存在,更新 vis 和 cnt
if(!vis[a]){
vis[a]=1;
cnt+=2;
}
//进行写入操作
ans[a]=cnt-1;
}
for(int i=1;i<=m;++i){
cout<<ans[i]<<' ';
}
return 0;
}
提交,嗯?\(40\) 分?
\(100\) 分做法
测一下样例二,就会发现,这份代码计算出的第六个和第十个文件大小计算错误。这是为什么呢?

其实,我们忽略了一个问题:文件名不一定只有一位数,可能是两位数甚至更多。这时,将 \(cnt\) 加上 \(2\) 就不对了,正确做法是加上 \(len + 1\)(\(len\) 表示文件名长度,\(1\) 是一个空格的长度)。
我们要再写一个函数,用来获取文件名长度(也就是文件名的位数)。这样就得出了满分代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
int n,m,ans[maxn];
bool vis[maxn];
//获取文件名长度
int get(int x){
int sum=0;
while(x){
x/=10;
++sum;
}
return sum;
}
int main(){
cin>>n>>m;
int a,cnt=0;
for(int i=1;i<=n;++i){
cin>>a;
//文件不存在,更新 vis 和 cnt
if(!vis[a]){
vis[a]=1;
cnt+=get(a);
++cnt;
}
//进行写入操作
ans[a]=cnt-1;
}
for(int i=1;i<=m;++i){
cout<<ans[i]<<' ';
}
return 0;
}

浙公网安备 33010602011771号