这是我悲惨的接近爆零的一次考试,但是本蒟蒻不能放弃,还是要总结的QAQ
答题卡 【题目背景】 八月是个悲惨的月份。先不谈炎热的天气,对于新生来说,八月意味着军训; 而对于高二高三的同学来说,八月意味着开学考试。而考试就意味着改卷,改卷 也就意味着答题卡。不幸的是,学校读答题卡的机器的评分软件坏了,wyx 就被 老师要求写一个评分的程序。 【问题描述】 软件需要读入学生的姓名、试题答案以及学生的答题卡信息。 学生姓名 学校的信息管理系统中存储了所有学生的姓名,一共 名学生。每个学生的 名字的组成只包含小写英文字母。如“a”,“hehe”,“nvshen”,“zouyuheng”, “lixuexin”都是符合要求的学生姓名。 试题答案 开学考试一共 道选择题,均为不定项选择题。选项共四个,A、B、C 和D, 标准答案选项的数量为1~4个。不同题目的分值可能不同。每道题有两个分值, 设为满分和部分分,保证部分分不超过满分。只有当学生的答案与标准答案完全 一致时才能获得满分;当学生的答案不与标准答案完全一致,但是没有选择错误 选项,且选择了至少一个选项时才能获得部分分;对于其他情况,不得分。比如: 试题答案选项为ACD,只有当学生答案为ACD时才能获得满分,如果学生答案 为A、C、D、AC、AD或CD则可以获得部分分,其他情况均不得分。 答题卡 一个学生的答题卡占四行,可以视为四个字符串。四个字符串从左往右数的 第 个空为第 题A、B、C 和D 这四个选项的方框是否被填涂,X 代表填涂,. 代表未填涂。比如: XX. .X. ... X.. 则表示第一题选择AD,第二题选择AB,而第三题没有选择。 请你根据上述的信息,计算每位学生的得分,并将学生按照成绩排序输出。 对于成绩相同的学生,按照学姓名的字典序升序输出。输入数据保证不存在重名 的情况。 CCF 全国信息学奥林匹克联赛(NOIP2014)复赛提高组Day1 模拟训练答题卡 第 3 页共8 页 【输入格式】 输入数据第一行包含两个整数 和 ,分别表示学生数和试题数。 接下来 行,每行有一个字符串,表示第 位同学的姓名。 接下来 行,每行描述一道试题。第 行有两个非负整数和一个字符串,分 别为第 道试题的满分、部分分以及答案串。答案串仅含有”A”、”B”、”C”和”D” 四种字符,且每个字符最多出现一次。答案串中含有的字符即为该题的答案选项。 在最后一道试题答案之后包含一个空行。 接下来 份答题卡,每份四行,按照读入顺序描述每一位学生的答题卡。两 份答题卡之间用一个空行隔开。 【输出格式】 输出一共 行,按照问题描述中排序的顺序输出 位学生的信息。每行首先 输出该学生的姓名,然后输出一个空格,再输出这位同学的成绩。 【样例输入】 3 4 zouyuheng lixuexin wangyingxu 10 1 ABCD 10 10 C 5 0 CD 10 5 ABD X..X X..X XXX. X.XX X..X X..X XXX. X.XX XXX. .XX. ...X .X.. CCF 全国信息学奥林匹克联赛(NOIP2014)复赛提高组Day1 模拟训练答题卡 第 4 页共8 页 【样例输出】 lixuexin 35 zouyuheng 35 wangyingxu 1 【样例说明】 在样例中,zouyuheng与lixuexin均获得满分,但由于lixuexin的字典 序更小,因此她排在他前面。而wangyingxu只有第一题部分正确,第二三四题 均错误,因此他的得分只有第一题的部分分1 分。 【数据规模与约定】 对于80%的数据,所有试题的答案选项只有一个,答题卡上每道题选择的选 项也只有一个且不存在两位同学得分相同的情况。 对于100%的数据, , ≤ 100,所有人的姓名长度不超过100
这道题呢其实就是个模拟,但是本蒟蒻挂了。。。导致整场考试几乎没分
怎么错的呢,没有把名字和分数打成结构体,排完分数最后直接把名字输出了,肯定是错的。。。。
然后改了两分钟八十了,为什么还有二十分挂了?
首先我的判分方式有问题,一旦这个人全都没涂,我给的还是满分,所以一个辅助变量解决,
所以思考一定要周全!!
然后呢还有一个事,就是题里要求升序输出,那么怎么升序呢
字典序是什么,就是字典里的顺序比如AB>ABC,AD>AEF
所以比较就是一位位往下扫,发现第一个不相等的决定他们两个之间的大小关系
就是这样(字典序和字符串长短没有半毛钱关系)
1 for(int i=1;i<=strlen(a.name+1);i++) 2 { 3 if(a.name[i]>b.name[i])return 0; 4 else if(a.name[i]return 1; 5 } 6 return 1;
T1代码
1 #include2 #include 3 #include 4 #define _ 0 5 using namespace std; 6 int n,m; 7 int man[150],part[150]; 8 struct node{int score;char name[150];}nd[150]; 9 bool operator<(node a,node b){ 10 if(a.score==b.score) 11 { 12 for(int i=1;i<=strlen(a.name+1);i++) 13 { 14 if(a.name[i]>b.name[i])return 0; 15 else if(a.name[i] return 1; 16 } 17 return 1; 18 } 19 return a.score>b.score; 20 } 21 bool an[150][5]; 22 char ans[150][5],work[5][150]; 23 int main() 24 { 25 freopen("sheet.in","r",stdin); 26 freopen("sheet.out","w",stdout); 27 scanf("%d%d",&n,&m); 28 for(int i=1;i<=n;i++)scanf("%s",nd[i].name+1); 29 for(int i=1;i<=m;i++) 30 { 31 scanf("%d%d%s",&man[i],&part[i],ans[i]+1); 32 for(int j=1;j<=strlen(ans[i]+1);j++) 33 { 34 if(ans[i][j]=='A')an[i][1]=1; 35 else if(ans[i][j]=='B')an[i][2]=1; 36 else if(ans[i][j]=='C')an[i][3]=1; 37 else if(ans[i][j]=='D')an[i][4]=1; 38 } 39 } 40 for(int st=1;st<=n;st++) 41 { 42 for(int i=1;i<=4;i++) 43 { 44 scanf("%s",work[i]+1); 45 } 46 for(int q=1;q<=m;q++) 47 { 48 int defen=2,tule=0; 49 for(int k=1;k<=4;k++) 50 { 51 if(work[k][q]=='X') 52 { 53 tule=1; 54 if(an[q][k]==0){defen=0;break;} 55 } 56 else 57 { 58 if(an[q][k]==1)defen=1; 59 } 60 } 61 if(tule==0)nd[st].score+=0; 62 else if(defen==0)nd[st].score+=0; 63 else if(defen==1)nd[st].score+=part[q]; 64 else if(defen==2)nd[st].score+=man[q]; 65 } 66 } 67 sort(nd+1,nd+n+1); 68 for(int i=1;i<=n;i++) 69 { 70 for(int k=1;k<=strlen(nd[i].name+1);k++)printf("%c",nd[i].name[k]); 71 printf(" %d\n",nd[i].score); 72 } 73 fclose(stdin); 74 fclose(stdout); 75 return ~~(0^_^0); 76 }
然后我们看T2
秘密邮件 【问题描述】 Sharon 收到了一封来自外星球的秘密邮件。邮件由n 个大写英文字母组成, 不巧的是Sharon 收到邮件以后一不小心打乱了原来的字母顺序。但是聪明的 Sharon 记住了原邮件的完整内容,现在她每次可以选择打乱后的邮件中相邻的 两个字母进行交换,问最少交换多少次能够将打乱的邮件恢复成原邮件。 【输入格式】 第一行一个整数n 表示邮件的长度。 第二行一个长度为n 的只包含大写字母的字符串表示打乱后的邮件。 第三行一个长度为n 的只包含大写字母的字符串表示原邮件。 为保证打乱后的邮件可以恢复成原邮件,所有的测试数据满足任意一种大写 字母在两封邮件中的出现次数相同。 【输出格式】 共一行包含一个整数,表示最少的交换次数。 【样例输入】 4 ABCD DBCA 【样例输出】 5 【样例说明】 第一次交换第一个和第二个字母得到BACD; 第二次交换第二个和第三个字母得到BCAD; 第三次交换第三个和第四个字母得到BCDA; 第四次交换第二个和第三个字母得到BDCA; 第五次交换第一个和第二个字母得到DBCA。 CCF 全国信息学奥林匹克联赛(NOIP2014)复赛提高组Day1 模拟训练秘密邮件 第 6 页共8 页 【数据规模与约定】 所有测试点的数据规模如下: 测试点编号n 的规模约定 1 n = 2 保证每种字母最 多只出现一次 2 n = 10 3 n = 15 4 n = 26 5 n = 5,000 保证最多只出现 两种字母6 n = 1,000,000 7 n = 1,000,000 8 n = 5,000 9 n = 1,000,000 / 10 n = 1,000,000
这道题本蒟蒻看了五分钟看出逆序对,然后呢,然后呢,然后挂了
逆序对怎么求?树状数组,这个木有问题
然后这道题对于重复字母有一些处理方法
这是一个小贪心,我们维护26个桶,把编号塞进里面
然后从桶底开始作为要求逆序对的数列,就OK
但是本蒟蒻卡了一些玄学的东西,不知道为什么就WA了,代码准度还是不够
T2代码
1 #include2 #include 3 #define N 1000011 4 using namespace std; 5 int n,bucket[30][N],cnt[30],ac[N],p[30],tree[N]; 6 long long ans; 7 char be[N],af[N]; 8 int lowbit(int a) 9 { 10 return a&(-a); 11 } 12 void add(int pos,int val) 13 { 14 for(int i=pos;i;i-=lowbit(i)) 15 { 16 tree[i]+=val; 17 } 18 } 19 int getsum(int pos) 20 { 21 int t = 0; 22 for(int i = pos;i<=n;i+=lowbit(i)) 23 { 24 t+=tree[i]; 25 } 26 return t; 27 } 28 int main() 29 { 30 freopen("letter.in","r",stdin); 31 freopen("letter.out","w",stdout); 32 scanf("%d",&n); 33 scanf("%s",be+1); 34 scanf("%s",af+1); 35 for(int i=1;i<=n;i++) 36 { 37 int now=be[i]-'A'+1; 38 cnt[now]++; 39 bucket[now][cnt[now]]=i; 40 } 41 for(int i=1;i<=n;i++) 42 { 43 int now=af[i]-'A'+1; 44 p[now]++; 45 ac[i]=bucket[now][p[now]]; 46 } 47 // for(int i=1;i<=n;i++)printf("%d ",ac[i]); 48 for(int i = 1;i<=n;i++) 49 { 50 ans+=getsum(ac[i]); 51 add(ac[i],1); 52 } 53 printf("%I64d\n",ans); 54 return 0; 55 }
我们看T3
庐州月 【引子】 桥上的恋人入对出双 桥边红药叹夜太漫长 月也摇晃 人也彷徨 乌蓬里传来了一曲离殇 庐州月光 洒在心上 月下的你不复当年模样 太多的伤 难诉衷肠 叹一句当时只道是寻常 庐州月光 梨花雨凉 如今的你又在谁的身旁 家乡月光 深深烙在我心上 却流不出当年泪光 ——Vae《庐州月》 【问题描述】 小 G 是出生在庐州的一位同学,当他高中毕业后,回到了自己的家乡。然 而家乡已不复当年模样,在高中表现优秀的小G 决定承担起家乡的一件重任, 那就是修理已经破烂不堪的石桥。 家乡中共有n 个石桥等待修理,对于第i 个石桥,我们定义两个参数pi,vi, 其中pi表示修理石桥的最小花费值,vi表示石桥需要的最小美化需求度。今天, 小G 已了解到修理厂共有m 种不同的修理原料,对于第i 种原料,可以对任意 一个石桥的美化度增加di,当然这也需要花费hi的费用。由于发货场的修理原料 有限,对于任意一种修理原料,只有一件,也就是说小G 只能选择购买和不购 买,对于第i 种修理材料能成功修理第j 个石桥的条件是:当且仅当hi ≥ pj,di ≥ vj。现在,已知这n 个石桥修理的最小花费值,最小美化需求度,以及m 种修理 原料的费用,可对石桥增加的美化度值,请你帮助小G完成这个修理任务。 【输入格式】 第一行包括两个正整数,n,m。 接下来n 行中,每行包括两个正整数pi,vi。 接下来m行中,每行包括两个正整数hi,di。 【输出格式】 只有一个整数,为最小修理花费。如果无法完成修理任务,则输出一个整数 -1。 CCF 全国信息学奥林匹克联赛(NOIP2014)复赛提高组Day1 模拟训练庐州月 第 8 页共8 页 【样例输入】 2 3 2 3 5 9 3 10 3 5 6 11 【样例输出】 9 【样例说明】 其中一种可行的方案是:使用第1 种材料,修理第1 个石桥,使用第3 种材 料,修理第2 个石桥,最小修理花费为3 + 6 = 9。 【数据规模与约定】 所有测试点的数据规模如下: 测试点编号n 的规模m的规模 1 n ≤ 10 m ≤ 10 2 n ≤ 10 m ≤ 10 3 n ≤ 10 m ≤ 10 4 n ≤ 10 m ≤ 10 5 n ≤ 20 m ≤ 20 6 n ≤ 30 m ≤ 30 7 n ≤ 40 m ≤ 40 8 n ≤ 50 m ≤ 50 9 n ≤ 500 m ≤ 500 10 n ≤ 1,000 m ≤ 1,000 11 n ≤ 1,500 m ≤ 1,500 12 n ≤ 2,000 m ≤ 2,000 13 n ≤ 20,000 m ≤ 20,000 14 n ≤ 30,000 m ≤ 30,000 15 n ≤ 40,000 m ≤ 40,000 16 n ≤ 60,000 m ≤ 60,000 17 n ≤ 70,000 m ≤ 70,000 18 n ≤ 80,000 m ≤ 80,000 19 n ≤ 100,000 m ≤ 100,000 20 n ≤ 100,000 m ≤ 100,000 对于全部测试数据满足1 ≤ n,m ≤ 100,000,1 ≤ pi,vi,di,hi ≤ 109
吐槽下出题人,竟然还写了一首诗。。
这道题呢,我考试时候用的stl,重载<号,死亡ing,把判断-1删除之后就得了60。。。
这道题的思路是什么呢,为什么会是O(能过)??
这道题的思路就是,先把需求和材料按美观度排序
然后外层枚举n,内层枚举m;
但是内层很巧妙,每次都把美观度大于当前需求的花费insert进set,然后lower_bound(得出第一个大于需要的花费)
这就是巧妙之处了,set里是不清空的,而且我已经预先把美观度排序了,所以set里的都是满足条件的,每次选第一个大于当前花费的就OK了
还有第二个巧妙之处,它的复杂度不是O(nm)的原因呢?内层的枚举不是1~n,是p~n,p每次insert都++,这样肯定小于O(nm)最坏情况为O(nlogm)
这道题之前做过原题但是我忘了。。。
T3代码
1 #include2 #include<set> 3 #include 4 #define N 100011 5 using namespace std; 6 int n,m,p=1; 7 long long ans; 8 struct node{int a,b;}n1[N],n2[N]; 9 bool cmp(node a,node b) 10 {return a.b>b.b;} 11 multiset<int>mm; 12 int main() 13 { 14 freopen("moon.in","r",stdin); 15 freopen("moon.out","w",stdout); 16 scanf("%d%d",&n,&m); 17 for(int i=1;i<=n;i++) 18 scanf("%d%d",&n1[i].a,&n1[i].b); 19 for(int i=1;i<=m;i++) 20 scanf("%d%d",&n2[i].a,&n2[i].b); 21 sort(n1+1,n1+n+1,cmp); 22 sort(n2+1,n2+m+1,cmp); 23 for(int i=1;i<=n;i++) 24 { 25 for(int j=p;j<=m;j++) 26 { 27 if(n2[j].b>=n1[i].b) 28 { 29 mm.insert(n2[j].a); 30 p++; 31 }else break; 32 } 33 multiset<int>::iterator it=mm.lower_bound(n1[i].a); 34 ans+=(long long)(*it); 35 mm.erase(it); 36 } 37 printf("%I64d",ans); 38 return 0; 39 }
革命尚未成功,本蒟蒻还需努力QAQ