LuoguP3692 夏幻的考试 题解
本蒟蒻甚至怀疑自己连个普及-的题目都做不出来了。。。然而还是做出来了
一道坑点多多的大模拟题目。
首先就是这道题目特有的cout<<endl
的问题,不过本人亲测发现好像这道题目与\n在Windows和Linux的兼容性没有太大的关系,用\n也能过得去本题。
然后开始盘点这道题目所有的过程。
\(Step~1\):输入
输入\(T,n\)倒是没有问题的。
关键是之后输入正确答案以及考号,考卷类型和每题的填涂答案的情况。首先是输入正确答案,用一个字符数组保存,然后用scanf("%s", ...)
读入就可以了(不过要注意下标!这个在AC代码里会有呈现)。
然后考号,直接定义一个大小为17的数组,然后用scanf("%1d", ...)
读入。
接着是考卷类型,也用同样方法输入。
最后是答案填涂,同样方法输入不啰嗦。
\(Step~2\):处理数据
我们发现考号的范围在十进制下的1到10000。然而在这里输入的是二进制。怎么办呢?我们用电脑自带的计算器查一下,发现10000在二进制下是这样的:
我们发现它只有14位数。
所以,我们可以想到这样一个特判:只要在16位二进制的第1、2位中有数,这个考号就是不合法的。
那么一般情况怎么弄呢?
很简单,直接通过位运算得到其十进制即可。
比如说\((1000010000)_2=1*2^9+1*2^4=528\)。
所以考号就这么处理完了。接下来判断就无需再讲了,一波if-else搞定。
然后是考卷类型。因为在题目中,0表示A卷,1表示B卷。所以,只要比对一下是否填涂且仅填涂了正确的考卷类型就行了。具体就是:如果根据考好得出是\(A\)卷,且试卷类型栏只填涂了\(A\)卷这个类型,就是\(Type~Correct\),或者得出是\(B\)卷,且试卷类型栏只填涂了\(B\)卷这个类型,也是\(Type~Correct\)。否则全部都是\(Type~Incorrect\)。
最后是考试答案。我们用一种类似于康托展开的方式,将每个填涂数据转化为一种状态,比如我们发现\(1000\)对应的是\(A\)这个答案,所以将这个填涂情况转换成\(1000\)这个数。
\(Step~3\):解决问题
首先考号,按照上面的处理方法判断。
然后考卷类型也是如此。
最后是考试答案。注意,在本人的代码中,正解答案的题目下标是\(0,1,2,...,n-1\),然而考生答案的题目下标是\(1,2,3,...n\)。所以需要注意一一比对。还有,因为本题中,默认满分是\(100\)分,所以每题积分直接取平均值,最好用\(double\)存储(精度高些)。
其他就没啥好讲了。总的来说,这个题目真心是个纯模拟题目,不过很多细节。祝大家刷题愉快!
最后来贴上正解代码~
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
using namespace std;
inline int read() {
int f = 1, x = 0;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
int T, n;
double per;
char correct[57];
struct node {
int id[17], A, B, ans[57][5], note[57];
}a[1007];
int main() {
T = read(), n = read();
per = 100.0 / (n * 1.0);
scanf("%s\n", correct);
// printf("%.1lf\n", per);
for(int i = 1; i <= T; ++i) {
int flag = 0, sum = 0;
for(int j = 1; j <= 16; ++j) {
scanf("%1d", &a[i].id[j]);
if((j == 1 || j == 2) && a[i].id[j]) flag = 1;
else {
// printf("%d ", 16 - j);
sum += a[i].id[j] * (int)pow(2, 16 - j);
// printf("%d\n", sum);
}
}
if(sum < 1 || sum > 10000) flag = 1;
scanf("%1d%1d", &a[i].A, &a[i].B);
for(int j = 1; j <= n; ++j)
for(int k = 1; k <= 4; ++k) {
scanf("%1d", &a[i].ans[j][k]);
a[i].note[j] = a[i].note[j] * 10 + a[i].ans[j][k];
}
if(flag) {
puts("Wrong ID\n");
continue;
}
printf("ID: %d\n", sum);
if((!a[i].id[16] && a[i].A && !a[i].B) || (a[i].id[16] && !a[i].A && a[i].B))
puts("Type Correct");
else
puts("Type Incorrect");
flag = 0; double num = 0.0;
for(int j = 1; j <= n; ++j) {
flag = 0;
// printf("%d %c\n", a[i].note[j], correct[j - 1]);
if(a[i].note[j] == 1000 && correct[j - 1] == 'A') num++;
else if(a[i].note[j] == 100 && correct[j - 1] == 'B') num++;
else if(a[i].note[j] == 10 && correct[j - 1] == 'C') num++;
else if(a[i].note[j] == 1 && correct[j - 1] == 'D') num++;
}
num *= per;
printf("%.1lf\n\n", num);
}
return 0;
}