NOIP(第11届)--2005--提高组--复赛--试题与答案(NA11)

2022-07-04 已有0人阅读 作者: IT航班

中小学编程红宝书.zip

关键词:

北京中关村;海淀黄庄;北京大学;清华大学。少儿编程;中小学编程;信息学竞赛;计算机竞赛;NOIP竞赛;CSP-J/S竞赛;NOI竞赛。2005年、提高组、复赛,第11届。


 

第1题:谁拿了最多奖学金

1、说明

A、试题类型:

       数学算法。

 

B、算法模型:

       STL深入。

 

C、试题说明:

       sort是个不稳定的排序。

stable_sort是稳定的排序。

2、代码

#include <bits/stdc++.h>

#include <algorithm>

#include <cmath>

#include <cstdio>

#include <cstring>

#include <deque>

#include <iostream>

#include <map>

#include <queue>

#include <set>

#include <stack>

#include <string>

#include <vector>

using namespace std;

 

typedef long long ll;

 

struct node

{

    char name[1000];

    int average;

    int class_grade;

    bool student_leader;

    bool student_west;

    int paper;

    int scholarship;

} p[105];

 

ll n, sum;

 

inline bool cmp(node a, node b)

{

    return a.scholarship > b.scholarship;

}

 

int main()

{

    cin >> n;

    for (int i = 0; i < n; ++i)

       {

        cin >> p[i].name;

        cin >> p[i].average;

        cin >> p[i].class_grade;

        string str;

        cin >> str;

        if (str[0] == 'Y')

              {

            p[i].student_leader = true;

        }

              else

              {

            p[i].student_leader = false;

        }

             

        cin >> str;

        if (str[0] == 'Y')

              {

            p[i].student_west = true;

        }

              else

              {

            p[i].student_west = false;

        }

             

        cin >> p[i].paper;

             

        if (p[i].average > 80 && p[i].paper >= 1)

              {

            p[i].scholarship += 8000;

        }

             

        if (p[i].average > 85 && p[i].class_grade > 80)

              {

            p[i].scholarship += 4000;

        }

             

        if (p[i].average > 90)

              {

            p[i].scholarship += 2000;

        }

             

        if (p[i].average > 85 && p[i].student_west)

              {

            p[i].scholarship += 1000;

        }

             

        if (p[i].class_grade > 80 && p[i].student_leader)

              {

            p[i].scholarship += 850;

        }

             

        sum += p[i].scholarship;

    }

      

    stable_sort(p, p + n, cmp);

      

    cout << p[0].name << endl;

    cout << p[0].scholarship << endl;

    cout << sum << endl;

      

    return 0;

}

 

第2题:过河

1、说明

A、试题类型:

       空间想象。

 

B、算法模型:

       离散化与动态规划应用。

 

C、试题说明:

基本思路:

对石头坐标排序;离散化并对石头对应位置打标记;

 

详细解释:

对石头坐标排序;题目没说读入时是有序的,所以要先排序,便于离散化。注意:读入

是直接保存坐标。离散化并对石头对应位置打标记。

 

为什么要离散化?

因为木桥的长度太大,没法用它去建立数组(就是dp要用),所以需要离散化。

 

怎么离散化?

当相邻的两块石头之间的距离过大时,有些距离是多余的,也就是说需要将这一段距离减掉。

 

距离有多长呢?2520

 

是1到10这10个数的最小公倍数。

 

跳的范围就是1到10的子区间,所以任意挑一个跳的距离,就可以一个石子不占的跳过去,并且对后面不会产生影响,所以这就是无用距离,减去即可。

 

注意,如果差距正好是2520的整数倍,那就要少减去一个2520,为了防止两块石头重叠。

 

打标记:

在另一个数组stone[]对应的处理后的坐标位置设置为1,代表有一个石头。

 

动态规划:

用f[i]表示到达i位置时,所要踩到的石头的最小数。

只需要枚举跳的范围。

 

状态转移方程应用。

2、代码

#include<bits/stdc++.h>

using namespace std;

 

int  minn,maxx,m,l,i,j,f[300000],a[1000],sum,k=0;

bool stone[300000];

 

int main()

{

    scanf("%d%d%d%d",&l,&minn,&maxx,&m);

 

    for (i=1;i<=m;++i)

       {

        scanf("%d",&a[i]);

    }

 

    sort(a+1,a+m+1);

 

    for (i=1;i<=m;++i)

       {

        if (a[i]-a[i-1]>2520)

              {

            k+=(a[i]-a[i-1])/2520;

            if((a[i]-a[i-1])%2520==0)

                     {

                   k--;

                     }

        }

        stone[a[i]-k*2520]=1;

    }

 

    memset(f,0x3f,sizeof(f));

    f[0]=0;

 

    for (i=1;i<=252000;++i)

       {

        for (j=maxx;j>=minn;--j)

              {

            if (i-j>=0)

                     {

                f[i]=min(f[i-j]+stone[i],f[i]);

            }

        }

    }

 

    printf("%d",f[252000]);

    return 0;

}

 

第3题:篝火晚会

1、说明

A、试题类型:

       基本算法。

 

B、算法模型:

       朴素算法。

 

C、试题说明:

首先,判断无解的情况:它相邻的不与它相邻。

 

然后,构造出合法的数列,因为第一位左边有两种选择,且构造出的环不等价,所以要做两次。

 

然后,考虑对于构造出的数列(断环为链),如何计算它与原数列的差别,即答案。

这是这道题最难的地方:如何 O(n)O(n) 的求出两个环的不同之处。

 

朴素算法:O(n2)O(n2),显然无法接受。

 

因为环无论怎么旋转,两个人的相对位置是不会变的,于是,可以对于每一个位置求出的数列与原数列的差 x,表示数列要旋转 x 个位置,此位置才会与原数列重合。

然后条统计出每个 x 出现的次数,nmax(x)nmax(x) 就是答案。

2、代码

#include <bits/stdc++.h>

using namespace std;

 

#define db double

#define ll long long

#define RG register

 

inline int gi()

{

    RG int ret; RG bool flag; RG char ch;

    ret=0, flag=true, ch=getchar();

 

    while (ch < '0' || ch > '9')

        ch == '-' ? flag=false : 0, ch=getchar();

 

    while (ch >= '0' && ch <= '9')

        ret=(ret<<3)+(ret<<1)+ch-'0', ch=getchar();

 

    return flag ? ret : -ret;

}

 

const db pi = acos(-1.0);

const int N = 5e4+5, inf = 1<<30;

 

int n,ans,f[N],s[N],pos[N],cnt[N];

bool vis[N];

 

inline void cal()

{

    RG int i;

    for (i=1; i<=n; ++i)

        cnt[(pos[i]-i+n)%n]++;

 

    for (i=0; i<n; ++i)

        ans=max(ans,cnt[i]), cnt[i]=0;

}

 

inline void dfs(RG int o,RG int dep)

{

    pos[dep]=o;

 

    if (dep == n)

        return cal();

 

    if (!vis[f[o]])

        vis[f[o]]=true, dfs(f[o],dep+1), vis[f[o]]=false;

 

    if (!vis[s[o]])

        vis[s[o]]=true, dfs(s[o],dep+1), vis[s[o]]=false;

}

 

int main()

{

    freopen("fire.in","r",stdin);

    freopen("fire.out","w",stdout);

 

    RG int i;

    n=gi();

    for (i=1; i<=n; ++i)

        f[i]=gi(), s[i]=gi();

 

    for (i=1; i<=n; ++i)

        if ((f[f[i]] != i  && s[f[i]] != i) || (f[s[i]] != i && s[s[i]] != i))

            return puts("-1"), 0;

 

    vis[1]=true;

    dfs(1,1);

 

    printf("%d\n",n-ans);

 

    return 0;

}

第4题:等价表达式

1、说明

A、试题类型:

       经典表达式。

 

B、算法模型:

       输入少得分就可以。

 

C、试题说明:

       输入有空格 还要考虑括号不匹配的情况。

 

此题的做法是将字母a设为1,2,3,4,5算出原式的值。

然后在将下面的表达式用a的1,2,3,4,5算出进行比较。

这样就变成了一般的表达式求值题。

由于算出数据可能很大 把算出的值每一步都取模。

2、代码

#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<algorithm>

#include<cstring>

#include<cmath>

using namespace std;

 

//小于 -->计算 大于-->入栈

char r[9][9] = {

       {' ','+','-','*','/','(',')','^','='},

             

       {'+','>','>','<','<','<','>','<','>'},

      

       {'-','>','>','<','<','<','>','<','>'},

      

       {'*','>','>','>','>','<','>','<','>'},

      

       {'/','>','>','>','>','<','>','<','>'},

      

       {'(','<','<','<','<','<','=','<',' '},

      

       {')','>','>','>','>',' ','>','>','>'},

      

       {'^','>','>','>','>','<','>','>','>'},

      

       {'=','<','<','<','<','<',' ','<','='},

      

};

 

char ss(char x,char y)

{

    int a,b;

    switch(x)

       {

       case '+':

              a=1;

              break;

       case '-':

              a=2;

              break;

       case '*':

              a=3;

              break;

       case '/':

              a=4;

              break;

       case '(':

              a=5;

              break;

       case ')':

              a=6;

              break;

       case '^':

              a=7;

              break;

       case '=':

              a=8;

              break;

    }

      

    switch(y)

       {

       case '+':

              b=1;

              break;

       case '-':

              b=2;

              break;

       case '*':

              b=3;

              break;

       case '/':

              b=4;

              break;

       case '(':

              b=5;

              break;

       case ')':

              b=6;

              break;

       case '^':

              b=7;

              break;

       case '=':

              b=8;

              break;

    }

    return r[a][b];

}

 

int ct(int x,int y,char ch)

{

    switch(ch)

       {

       case '+':

              return (x+y)%10007;

              break;

       case '-':

              return (x-y)%10007;

              break;

       case '*':

              return (x*y)%10007;

              break;

       case '/':

              return (x/y)%10007;

              break;

       case '^':

              if(x==0) return 0;

              if(y==0) return 1;

              int c=1;

              for(int i=1;i<=y;i++){

                     c*=x;

                     c%=10007;

                     //由于乘方可能很大 所以每部都求余 不能使用pow了

              }

              return c;

              break;

    }

}

 

int opd[100],topd,topr=1,a,b,c;

char opr[100],ch,cch;

char s[55];

int ans[10];

 

int deal(int i)

{//因为要处理多次 将过程化为函数 i即a的值

       int t=0;

       topr=1,topd=0;

       opr[1]='=';

       ch=s[t++];

       int flag=0;

       while(!(ch=='='&&opr[topr]=='='))

       {

              if(ch>='0'&&ch<='9'&&flag==0)

              {

                     opd[++topd]=ch-48;

                     ch=s[t++];

                     flag=1;

              }

              while(ch>='0'&&ch<='9'&&flag==1)   

              {

                     int x=opd[topd--];

                     x=x*10+ch-48;

                     opd[++topd]=x;

                     ch=s[t++];

              }

             

              flag=0;

              if(ch=='a')

              {

                     opd[++topd]=i;

                     ch=s[t++];

              }

             

              //这里加一个判断 如果不加 输入单个数字的时候会卡死(等号不进行判断):

              if(ch=='='&&opr[topr]=='=')

                     return opd[1];

             

              else if(!(ch>='0'&&ch<='9'))

            switch(ss(opr[topr],ch))

              {

                case '<':

                    opr[++topr]=ch;

                    ch=s[t++];

                    break;

                case '>':

                    a=opd[topd--];

                    b=opd[topd--];

                    cch=opr[topr--];

                    c=ct(b,a,cch);

                    opd[++topd]=c;

                    break;

                case '=':

                    topr--;

                    ch=s[t++];

                    break;

              }

       }

       return opd[1];

}

 

char temp[55];

 

void makeinput()

{//此函数是为了读入 过滤其空格

    gets(temp);

    int p=0;

    int len=strlen(temp);

    for(int i=0;i<len;i++)

       {

        if(temp[i]==' ') continue;

        s[p++]=temp[i];

    }

    s[p]='=';

    s[p+1]='\0';

}

 

int main()

{

    //freopen("equal8.in","r",stdin);

    //freopen("answer.txt","w",stdout);

    makeinput();

    for(int i=1;i<=5;i++)

       {

        ans[i]=deal(i);

    }

      

    int n;

    int pd=0;

    scanf("%d",&n);

    getchar();//这里的getchar很重要

    for(int i=1;i<=n;i++)

       {

        pd=0;

        makeinput();

        for(int j=1;j<=5;j++)

              {

            int k=deal(j);

            //cout<<k<<endl;

            if(k!=ans[j])

            {

                pd=1;

                break;

            }

        }

             

        if(pd==1)

                     continue;

        else if(pd==0){

            printf("%c",i+64);

        }

    }

    return 0;

}

      

 

IT航班支持----中小学编程比赛汇总:

 

第一部分:国内比赛(IT航班支持)   

1、软件能力认证(CSP-JS) 

2、全国青少年信息学奥林匹克联赛(NOIP)    

3、全国青少年信息学奥林匹克竞赛(NOI)

4、中国青少年………………………  

5、………………………创新挑战赛  

6、全国青少年………………………  

7、………………………

8、 恩欧希教育信息化发明创新奖  

9、世界机器人大赛(WRC) 

10、………………………大赛    

11、少………………………智能教育成果展示大赛 

12、“明天小小科学家”奖励活动

13、………………………    

14、………………………    

15、国际信息学……………………… 

16、………………………    

 

第二部分:国际比赛(IT航班支持)   

17、………………………    

18、国际………………………    

19、………………………

20、美国信息学……………………… 

21、加拿大……………………… 

22、官方邀请赛 (CCO)     

23、国际计算思维………………………    

24、美国计算机……………………… 

25、澳大利亚………………………    

 

第三部分:企业比赛(IT航班支持)   

26、微软MTA    

27、………………………挑战赛 

28、………………………科学奖 

29、………………………学奖    

30、………………………创新挑战赛 

31、………………………挑战赛 

32、………………………芯计算机表演赛 

33、………………………大赛    

 

第四部分:Scratch相关竞赛(IT航班支持)    

34、全国中小学生电脑制作大赛     

35、………………………    

36、………………………    

37、………………………    

 

第五部分:其它(IT航班支持)   

38、NOI夏令营  

39、NOI冬令营(NOIWC)  

40、全国青少年……………………… 

41、国际青少年………………………

 

联系方式:

A、官方网址:

http://www.itflight.net


B、微信公众号:

添加微信,获取资料。

image.png

 



关注公众号,获取动态。

image.png