zoukankan      html  css  js  c++  java
  • 【2018.12.15】【考试总结】【模拟+逆序对+树状数组+贪心+multiset】爆零之旅

    这是我悲惨的接近爆零的一次考试,但是本蒟蒻不能放弃,还是要总结的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
    T1

     这道题呢其实就是个模拟,但是本蒟蒻挂了。。。导致整场考试几乎没分

    怎么错的呢,没有把名字和分数打成结构体,排完分数最后直接把名字输出了,肯定是错的。。。。

    然后改了两分钟八十了,为什么还有二十分挂了?

    首先我的判分方式有问题,一旦这个人全都没涂,我给的还是满分,所以一个辅助变量解决,

    所以思考一定要周全!!

    然后呢还有一个事,就是题里要求升序输出,那么怎么升序呢

    字典序是什么,就是字典里的顺序比如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]<b.name[i])return 1;
    5 }
    6 return 1;

     T1代码

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     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]<b.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
    ",nd[i].score);
    72     }
    73     fclose(stdin);
    74     fclose(stdout);
    75     return ~~(0^_^0);
    76 }
    View Code

    然后我们看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
    T2

     这道题本蒟蒻看了五分钟看出逆序对,然后呢,然后呢,然后挂了

    逆序对怎么求?树状数组,这个木有问题

    然后这道题对于重复字母有一些处理方法

    这是一个小贪心,我们维护26个桶,把编号塞进里面

    然后从桶底开始作为要求逆序对的数列,就OK

    但是本蒟蒻卡了一些玄学的东西,不知道为什么就WA了,代码准度还是不够

     T2代码

     1 #include<cstdio>
     2 #include<cstring>
     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
    ",ans);
    54     return 0;
    55 }
    View Code

    我们看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,0001 ≤ pi,vi,di,hi ≤ 109
    T3

     吐槽下出题人,竟然还写了一首诗。。

    这道题呢,我考试时候用的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 #include<cstdio>
     2 #include<set>
     3 #include<algorithm>
     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 }
    View Code

     革命尚未成功,本蒟蒻还需努力QAQ

  • 相关阅读:
    UVA11464偶数矩阵
    UVA11464偶数矩阵
    UVA11462年龄排序
    UVA11462年龄排序
    UVA11427玩纸牌(全概率+递推)
    UVA11427玩纸牌(全概率+递推)
    UVA11389巴士司机问题
    LA3644简单并查集判环
    LA3027简单带权并查集
    LA3027简单带权并查集
  • 原文地址:https://www.cnblogs.com/Qin-Wei-Kai/p/10143983.html
Copyright © 2011-2022 走看看