NOIP(第20届)--2014--提高组--复赛--试题与答案(NA20)

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

中小学编程红宝书.zip

 


第1题(day1):生活大爆炸版石头剪刀布

1、说明

A、试题类型:

       送分题。

 

B、算法模型:

       无。

 

C、试题说明:

       读题。

2、代码

#include<iostream>

using namespace std;

 

int n, a[200], b[200],na,nb,c,d;

 

void initialize()

{

       int i;

       cin >> n >> na >> nb;

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

              cin >> a[i];

       for (; i < n; i++)

              a[i] = a[i - na];

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

              cin >> b[i];

       for (; i < n; i++)

              b[i] = b[i - nb];

}

 

void compare(int x,int y)

{

       switch (x)

       {

       case 0:

              switch (y)

              {

              case 1:

              case 4:d++; break;

              case 2:

              case 3:c++; break;

              }

              break;

              case 1:

                     switch (y)

                     {

                     case 2:

                     case 4:d++; break;

                     case 0:

                     case 3:c++; break;

                     }

                     break;

                     case 2:

                            switch (y)

                            {

                            case 0:

                            case 3:d++; break;

                            case 1:

                            case 4:c++; break;

                            }

                            break;

                            case 3:

                                   switch (y)

                                   {

                                   case 1:

                                   case 0:d++; break;

                                   case 2:

                                   case 4:c++; break;

                                   }

                                   break;

                                   case 4:

                                          switch (y)

                                          {

                                          case 2:

                                          case 3:d++; break;

                                          case 0:

                                          case 1:c++; break;

                                          }

       }

}

 

void operate()

{

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

              compare(a[i], b[i]);

}

 

void show()

{

       cout << c << ' ' << d;

}

 

int main()

{

       initialize();

       operate();

       show();

       return 0;

}

第2题(day1):联合权值

1、说明

A、试题类型:

       结构与算法。

 

B、算法模型:

       暴力dfs,暴力hash。

 

C、试题说明:

       树编程。

 

 

 

 

int s=0;

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

{

    sum=(sum+s*r[i])%P;

    s=(s+r[i])%P;

}

2、代码

#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<algorithm>

#define P 10007

#define M 2000005

using namespace std;

 

struct link

{

    int u,v,w;

}l[M];

 

int n,t,ans,sum,r[M],w[M];

 

bool com(link a,link b)

{

    return  a.u>b.u;

}

 

void work(int k)

{

    int s=0;

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

    {

        sum=(sum+s*r[i])%P;

        s=(s+r[i])%P;

    }

    int mx1=0,mx2=0,x=0;

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

    {

        if(r[i]>mx1)

        {

            mx1=r[i];

            x=i;

        }

    }

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

        if(i!=x)mx2=max(mx2,r[i]);

              ans=max(ans,mx1*mx2);

}

 

int main()

{

    cin>>n;

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

    {

        scanf("%d%d",&l[i*2].u,&l[i*2].v);

        l[i*2-1].v=l[i*2].u;

        l[i*2-1].u=l[i*2].v;

    }

      

    for(int i=1;i<=n;i++)scanf("%d",&w[i]);

    sort(l+1,l+2*n+1,com);

      

    int j=0;

      

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

    {

        if(i==1||l[i].u==l[i-1].u)

            r[++j]=w[l[i].v];

        else

        {

            work(j);

            j=0;

            r[++j]=w[l[i].v];

        }

    }

      

    work(j);

    sum=(sum*2)%P;

    cout<<ans<<' '<<sum;

}

第3题(day1):飞扬的小鸟

1、说明

A、试题类型:

       生活应用。

 

B、算法模型:

       背包问题与方程不等式。

 

C、试题说明:

读完题可以发现,每次点击可以分为两种背包,向上为完全背包,向下为0/1背包,那么就可以把每一个横坐标的答案分为两个背包来求解。

 

 f[i][j]表示坐标为(i,j)的点最少需要多少次。

 

 转移方程为:f[i][j]=min(f[i-1][j-up[i]*k]+k)。

 

 这样做的效率为n^3的,肯定没有分数。

 

 考虑优化,发现f[i][j-up[i]*k]+k可以从f[i][j-up[i]*(k-1)]+k-1转移。

 

 所以转移方程变为:f[i][j]=min(f[i-1][j-up[i]])。

 

 最后注意到达m是不能继续向上飞的条件。

2、代码

#include<bits/stdc++.h>

using namespace std;

 

const int max_n = 10010;

const int max_m = 1010;

const int inf   = 1e9+7;

 

struct node

{

       int pos,l,h;

}a[max_n];

 

int f[2][max_m],up[max_n],down[max_n];

int n,m,t,num=1,ans=inf,k;

 

inline bool cmp(node a,node b)

{

       return a.pos<b.pos;

}

 

inline void dp()

{

       int tmp=0;

      

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

       {

              tmp^=1;

              for(int j=0; j<=m; ++j)

                     f[tmp][j]=inf+m;

             

              for(int j=up[i]+1; j<=m; ++j)

                     f[tmp][j]=min(f[tmp][j],min(f[tmp^1][j-up[i]]+1,f[tmp][j-up[i]]+1));

             

              for(int j=up[i]+1; j<=m; ++j)

                     if(i==a[num].pos && !(j>a[num].l && j<a[num].h)) f[tmp][j]=inf+m;

                     for(int j=m-up[i]; j<=m; ++j)

                            f[tmp][m]=min(f[tmp][m],min(f[tmp^1][j]+1,f[tmp][j]+1));

                    

                     if(i==a[num].pos && !(m>a[num].l && m<a[num].h))

                            f[tmp][m]=inf+m;

                    

                     for(int j=1; j<=m-down[i]; ++j)

                     {

                            f[tmp][j]=min(f[tmp][j],f[tmp^1][j+down[i]]);

                           

                            if(i==a[num].pos && !(j>a[num].l && j<a[num].h))

                                   f[tmp][j]=inf+m;

                     }

                     if(a[num].pos==i)

                     {

                            for(int j=a[num].l+1; j<a[num].h; ++j)

                                   if(f[tmp][j]<inf)

                                   {

                                          k=num;

                                          break;

                                   }

                                   num++;

                     }

       }

}

 

inline void get_ans()

{

       int tmp=n%2;

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

              ans=min(ans,f[tmp][i]);

}

 

int main()

{

       scanf("%d%d%d",&n,&m,&t);

      

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

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

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

              scanf("%d%d%d",&a[i].pos,&a[i].l,&a[i].h);

      

       sort(a+1,a+t+1,cmp);

       dp();

       get_ans();

       if(ans<inf)

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

       else

              printf("0\n%d\n",k);

      

       return 0;

}

 

第1题(day2):无线网络发射器选址

1、说明

A、试题类型:

       基本算法。

 

B、算法模型:

       暴力枚举,搜索。

 

C、试题说明:

       循环控制,划定范围。然后逐次枚举。

 

 

2、代码

#include<cstdio>

using namespace std;

 

int d,n,a[300][300],cnt,maxm=-1,x,y,k;

 

int main()

{

    scanf("%d%d",&d,&n);

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

    {

        scanf("%d %d",&x,&y);

        scanf("%d",&a[x+20][y+20]);

    }

      

    for(int i=0+20;i<=128+20;i++)

        for(int j=0+20;j<=128+20;j++)

        {

            int sum=0;

            for(int u=i-d;u<=i+d;u++)

                            for(int v=j-d;v<=j+d;v++)

                                   sum=sum+a[u][v];

                            if(sum==maxm)cnt++;

                            if(sum>maxm){maxm=sum; cnt=1;}

        }

             

              printf("%d %d",cnt,maxm);

             

              return 0;

}

第2题(day2):寻找道路

1、说明

A、试题类型:

       最短路径。

 

B、算法模型:

       bfs。

 

C、试题说明:

       这里用 h1 储存所有边,h2 储存所有逆向边。

1、反向bfs一次,即可得到每个点能否到达终点 t,记为 flag[i]。

2、求 s 到 t 的最短路,由于每条边的长度都是1,可以直接采用bfs来做。

正向与逆向都可以。

2、代码

#include<cstdio>

#include<cstring>

#include<cctype>

#include<algorithm>

using namespace std;

 

const int maxn=1e4;

int q[maxn+10];

bool flag[maxn+10],used[maxn+10];

 

struct tnode

{

       int d;

       tnode *next;

}*h1[maxn+10],*h2[maxn+10];

 

int getin()

{

       int ans=0;

       char tmp;

      

       while(!isdigit(tmp=getchar()));

      

       do ans=(ans<<3)+(ans<<1)+tmp-'0';

      

       while(isdigit(tmp=getchar()));

      

       return ans;

}

 

void add1(int u,int v)

{

       tnode *p=new tnode;

       (*p).d=v,(*p).next=h1[u],h1[u]=p;

}

 

void add2(int u,int v)

{

       tnode *p=new tnode;

       (*p).d=v,(*p).next=h2[u],h2[u]=p;

}

 

bool ok(int u)

{

       if(!flag[u] || used[u])

              return 0;

      

       tnode *p=h1[u];

      

       while(p)

    {

              if(!flag[(*p).d])

                     return 0;

             

              p=(*p).next;

       }

       return 1;

}

 

int main()

{

       int n,m,i,x,y,s,t,l,r,k,ans=0;

       tnode *p;

       n=getin(),m=getin();

      

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

    {

              x=getin(),y=getin();

              add1(x,y),add2(y,x);

    }

       s=getin(),t=getin();

      

       l=r=1,q[1]=t,flag[t]=1;

      

       while(l<=r)

    {

              p=h2[q[l]],l++;

              while(p)

        {

                     if(!flag[(*p).d])

                            q[++r]=(*p).d,flag[(*p).d]=1;

                     p=(*p).next;

              }

       }

      

       if(!flag[s])

       {

              printf("-1\n");

              return 0;

       }

      

    

       l=r=1,q[1]=t,k,used[t]=1;

      

       while(l<=r)

    {

              for(i=l,k=r;i<=k;i++)

                     for(p=h2[q[i]];p;p=(*p).next)

                     {

                            if(!ok((*p).d))continue;

                            if((*p).d==s)

                            {

                                   printf("%d\n",ans+1);return 0;

                            }

                            q[++r]=(*p).d,used[q[r]]=1;

                     }

                     l=k+1,ans++;

       }

       printf("-1\n");

      

       return 0;

}

第3题(day2):解方程

1、说明

A、试题类型:

       解方程 + 数论 + 模拟。

 

B、算法模型:

       暴力,秦九韶。

 

C、试题说明:

       题目大意:求一个多项式方程在[ 1 , m ] [1, m][1,m]的整数解。

 

要用到一个算法:秦九韶算法,就是减少多项式的计算次数。

然后暴力枚举[ 1 , m ] [1, m][1,m]。

 

由于系数太大,还要取模。将原数分别模多个质数,如果答案都为0是就可以近似认为是答案了。

 

满分做法:

注意到在模p意义下若f ( x ) = 0f。

则f ( x + k ∗ p ) = 0。

所以只用枚举到质数范围就行了。

2、代码

#include<cstdio>

#include<cstring>

const int MOD[3] = {20029,22277,23333};

const int MaxMod = 3;

 

int n, m;

char ch[20001];

long long a[5][105];

int Mod[5][40001];

int ans[1000001];

 

inline void read(int i)

{

       int f = 1; char ch = getchar();

      

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

       {

              if(ch == '-')

                     f = -1;

              ch = getchar();

       }

      

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

       {

              for(int t = 0; t < MaxMod; t++)

                     a[t][i] = (a[t][i] * 10 + ch - '0') % MOD[t];

              ch = getchar();

       }

      

       if(f == -1)

              for(int t = 0; t < MaxMod; t++)

                     a[t][i] = MOD[t] - a[t][i];

}

 

inline bool pd(int x, int t)

{

       long long sum = a[t][n];

       for(int i = n - 1; i >= 0; i--)

              sum = (sum * x + a[t][i]) % MOD[t];

      

       return sum == 0;

}

 

inline bool check(int x)

{

       for(int t = 0; t < MaxMod; t++)

              if(!Mod[t][x % MOD[t]])

                     return false;

              return true;

}

 

int main()

{

       scanf("%d%d", &n, &m);

      

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

      

       for(int t = 0; t < MaxMod; t++)//枚举MOD

              for(int x = 1; x < MOD[t]; x++)//枚举x

                     if(pd(x, t))

                            Mod[t][x] = true;

                     for(int x = 1; x <= m; x++)

                            if(check(x))

                                   ans[++ans[0]] = x;

                            printf("%d\n", ans[0]);

                            for(int i = 1; i <= ans[0]; i++)

                                   printf("%d\n", ans[i]);

                           

                            return 0;

}


IT航班提供:教辅资料、课程视频、课程书籍、竞赛辅导、少儿编程指导、课程采购、加盟、少儿编程资料、少儿编程课程、保送生、特长生、加分、中小学计算机教育、中小学信息学、竞赛、中小学信息学课程、人工智能、中小学编程加盟、少儿编程加盟、品牌加盟、技术加盟、技术指导、课程加盟、师资培训、中小学编程教辅资料、中小学编程教师培训、少儿编程教学书籍、少儿编程视频、教学书籍、教师培训、教学视频、CSP-J/S、中小学信息学课程服务、竞赛指导、课程提供、国内外计算机中小学计算机竞赛、信息学竞赛、信息学课程提供商、信息学奥林匹克。

      

 

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