NOIP(第22届)--2016--提高组--复赛--试题与答案(NA22)

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

中小学编程红宝书.zip

 


第1题(day1):玩具谜题

1、说明

A、试题类型:

       送分题。

 

B、算法模型:

       模拟。

 

C、试题说明:

       条件结构和循环。每次是往顺时针或逆时针来转,仔细观察可以发现,如果方向与左右手相同的话,就是加,不然就是减。

 

2、代码

#include<bits/stdc++.h>

#define N 100000

using namespace std;

 

int n,dir[N+5],tmp,s,m;

int pos;

char name[N+5][15];

 

int main()

{

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

      

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

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

              scanf("%d %s\n",&dir[i],name[i]);

      

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

    {

        scanf("%d%d",&tmp,&s);

        if(tmp!=dir[pos])pos=(pos+s)%n;

        else pos=(pos-s+n)%n;

    }

      

    cout<<name[pos];

    return 0;

}

第2题(day1):天天爱跑步

1、说明

A、试题类型:

       基本算法。

 

B、算法模型:

       DFS。

 

C、试题说明:

       dfs序——将求子树的信息(树形)转化为求一段连续区间信息(线形)。

线段树——求区间信息。

树上差分——统计答案。

lca——拆分路径。

树链剖分——求lca。

 

 

2、代码

#include<cstdio>

#include<cstring>

#include<algorithm>

#define N 300401

using namespace std;

 

int n,m,fa[N],son[N],deep[N],bl[N],sz,id[N],ans[N];

int in[N],out[N],watch[N];

int front[N],nextt[N*2],to[N*2];

int root[N*3],lc[N*25],rc[N*25],sum[N*25],tot,cnt;

 

struct node

{

    int s,t,lca;

}runner[N];

 

void add(int u,int v)

{

    to[++cnt]=v; nextt[cnt]=front[u]; front[u]=cnt;

}

 

void dfs1(int now)

{

    son[now]++;

    for(int i=front[now];i;i=nextt[i])

    {

        if(to[i]==fa[now])

                     continue;

             

        deep[to[i]]=deep[now]+1;

        fa[to[i]]=now;

        dfs1(to[i]);

        son[now]+=son[to[i]];

    }

}

 

void dfs2(int now,int chain)

{

    id[now]=++sz;

    in[now]=sz;

    bl[now]=chain;

    int y=0;

    for(int i=front[now];i;i=nextt[i])

    {

        if(to[i]==fa[now])

                     continue;

             

        if(son[to[i]]>son[y])

                     y=to[i];

    }

    if(!y)

    {

        out[now]=sz;

        return;

    }

    dfs2(y,chain);

    for(int i=front[now];i;i=nextt[i])

    {

        if(to[i]==fa[now]||to[i]==y)

                     continue;

             

        dfs2(to[i],to[i]);

       }

       out[now]=sz;

}

 

int getlca(int u,int v)

{

    while(bl[u]!=bl[v])

    {

        if(deep[bl[u]]<deep[bl[v]])

                     swap(u,v);

             

        u=fa[bl[u]];

    }

    return deep[u]<deep[v] ? u:v;

}

void change(int & now,int l,int r,int pos,int w)

{

    if(!pos)

              return;

      

    if(!now)

              now=++tot;

      

    sum[now]+=w;

      

    if(l==r)

              return;

      

    int mid=l+r>>1;

      

    if(pos<=mid)

              change(lc[now],l,mid,pos,w);

    else

              change(rc[now],mid+1,r,pos,w);

}

 

int query(int now,int l,int r,int opl,int opr)

{

    if(!now)

              return 0;

      

    if(l==opl&&r==opr)

              return sum[now];

      

    int mid=l+r>>1;

      

    if(opr<=mid)

              return query(lc[now],l,mid,opl,opr);

    else if(opl>mid)

              return query(rc[now],mid+1,r,opl,opr);

    else

              return query(lc[now],l,mid,opl,mid)+query(rc[now],mid+1,r,mid+1,opr);

}

 

void clear()

{

    tot=0;

    memset(lc,0,sizeof(lc));

    memset(rc,0,sizeof(rc));

    memset(sum,0,sizeof(sum));

    memset(root,0,sizeof(root));

}

int main()

{

/*freopen("runninga.in","r",stdin);

    freopen("runninga.out","w",stdout);*/

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

    int u,v;

      

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

    {

        scanf("%d%d",&u,&v);

        add(u,v);add(v,u);

    }

      

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

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

      

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

              scanf("%d%d",&runner[i].s,&runner[i].t);

      

    dfs1(1);

    dfs2(1,0);

      

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

              runner[i].lca=getlca(runner[i].s,runner[i].t);

      

    int now;

      

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

    {

        now=deep[runner[i].s];

        change(root[now],1,n,id[runner[i].s],1);

        change(root[now],1,n,id[fa[runner[i].lca]],-1);

    }

      

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

              ans[i]=query(root[deep[i]+watch[i]],1,n,in[i],out[i]);

      

    clear();

      

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

    {

        now=deep[runner[i].s]-deep[runner[i].lca]*2+n*2;

        change(root[now],1,n,id[runner[i].t],1);

        change(root[now],1,n,id[runner[i].lca],-1);

    }

      

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

              ans[i]+=query(root[watch[i]-deep[i]+n*2],1,n,in[i],out[i]);

      

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

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

}

第3题(day1):换教室

1、说明

A、试题类型:

       动态规划。

 

B、算法模型:

       多方程推导。

 

C、试题说明:

先用Floyd预处理任意两点x,y之间的最短路d[x][y]。

 

设f[ i ][ j ][ k ]表示当前是第i天,一共换了j间教室,k=0或1表示第i天是否换了教室

k[i]表示第i天换教室成功的概率。

 

c[i][0]表示第i天换前的教室,c[i][1]表示第i天换后的教室。

 

有以下四种情况:

情况一:第i-1天换了教室,第i天未换教室;

情况二:第i-1天换了教室,第i天换了教室;

情况三:第i-1天未换教室,第i天未换教室;

情况一:第i-1天未换教室,第i天换了教室;

 

初始状态:

f[i][j][k]=inf(极大值)

f[1][0][0]=0; f[1][1][1]=0;

 

状态转移方程:

f[i][j][0]=min(f[i][j][0],f[i-1][j][1]+k[i-1]*d[c[i-1][1]][c[i][0]]+(1-k[i-1])*d[c[i-1][0]][c[i][0]]);

f[i][j][0]=min(f[i][j][0],f[i-1][j][0]+d[c[i-1][0]][c[i][0]]);

if(j!=0){

f[i][j][1]=min(f[i][j][1],f[i-1][j-1][0]+k[i]*d[c[i-1][0]][c[i][1]]+(1-k[i])*d[c[i-1][0]][c[i][0]]);

f[i][j][1]=min(f[i][j][1],f[i-1][j-1][1]+k[i]*k[i-1]d[c[i-1][1]][c[i][1]]+k[i](1-k[i-1])*d[c[i-1][0]][c[i][1]]+(1-k[i])*k[i-1]d[c[i-1][1]][c[i][0]]+(1-k[i])(1-k[i-1])*d[c[i-1][0]][c[i][0]]);

}

2、代码

#include<bits/stdc++.h>

using namespace std;

 

const int N=2005;

const double maxi=800050000;

 

int n,m,v,e;

int c[N][2];

double k[N];

double d[N][N];

double f[N][N][2];

 

int read()

{

       int sum=0,f=1;

       char ch=getchar();

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

       {

              if(ch=='-')f=-1;

              ch=getchar();

       }

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

       {

              sum=(sum<<3)+(sum<<1)+ch-'0';

              ch=getchar();

       }

       return sum*f;

}

 

int main()

{

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

       //    freopen("classroom.out","w",stdout);

       n=read();

       m=read();

    v=read();

    e=read();

      

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

              c[i][0]=read();

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

              c[i][1]=read();

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

              scanf("%lf",&k[i]);

      

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

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

                     d[i][j]=d[j][i]=maxi;

              int x,y;

              double w;

             

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

              {

                     x=read();

                     y=read();

                     scanf("%lf",&w);

                    

                     if(w<d[x][y])

                            d[x][y]=d[y][x]=w;

              }

             

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

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

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

                                   if(d[i][j]>d[i][t]+d[t][j])

                                          d[i][j]=d[j][i]=d[i][t]+d[t][j];

                                  

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

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

                                                 f[i][j][0]=f[i][j][1]=maxi;

                                          f[1][0][0]=0;

                                          f[1][1][1]=0;

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

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

                                                 {

                                                        f[i][j][0]=min(f[i][j][0],f[i-1][j][1]+k[i-1]*d[c[i-1][1]][c[i][0]]+(1-k[i-1])*d[c[i-1][0]][c[i][0]]);

                                                        f[i][j][0]=min(f[i][j][0],f[i-1][j][0]+d[c[i-1][0]][c[i][0]]);

                                                        if(j!=0)

                                                        {

                                                               f[i][j][1]=min(f[i][j][1],f[i-1][j-1][0]+k[i]*d[c[i-1][0]][c[i][1]]+(1-k[i])*d[c[i-1][0]][c[i][0]]);

                                                               f[i][j][1]=min(f[i][j][1],f[i-1][j-1][1]+k[i]*k[i-1]*d[c[i-1][1]][c[i][1]]+k[i]*(1-k[i-1])*d[c[i-1][0]][c[i][1]]+(1-k[i])*k[i-1]*d[c[i-1][1]][c[i][0]]+(1-k[i])*(1-k[i-1])*d[c[i-1][0]][c[i][0]]);

                                                        }

                                                 }

 

                                                 double ans=maxi;

 

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

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

                                                        {

                                                               ans=min(ans,f[n][j][t]);

                                                        }

                                                        printf("%.2lf",ans);

                                                        return 0;

}

 

第1题(day2):组合数问题

1、说明

A、试题类型:

       数字问题。

 

B、算法模型:

       组合数。

 

C、试题说明:

       无。

 

2、代码

#include<bits/stdc++.h>

using namespace std;

#define ll long long

ll c[2005][2005],f[2005][2005];

int m,n,k,t;

inline int read()

{

    char ch=getchar();

    int res=0;

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

    while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();

    return res;

}

 

inline void init()

{

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

              c[i][1]=i,c[i][0]=1;

      

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

       {

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

              {

            c[i][j]=c[i-1][j-1]+c[i-1][j];

            c[i][j]%=k;

        }

    }

      

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

       {

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

              {

            f[i][j]=f[i][j-1]+(c[i][j]%k==0);

        }

    }

}

 

int main()

{

    t=read(),k=read();

    init();   

    while(t--)

       {

        n=read(),m=read();

        m=min(m,n);

        ll ans=0;

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

              {

            int h=min(m,i);

            ans+=f[i][h];

        }

        cout<<ans<<'\n';

    }

}

第2题(day2):蚯蚓

1、说明

A、试题类型:

       基本数据结构。

 

B、算法模型:

       队列。

 

C、试题说明:

       可以用优先队列实现,但是要优化一下。考虑每次取出一个最大值这个操作,堆来维护比较方便,但是每次加上一个似乎不好处理。

 

考虑增加一个全局变量,表示每个数都需要加上,这样就可以避免对于堆中所有元素增加,而只需把每次新的两个元素减去,再放入堆中即可。

 

具体做法:系统堆维护,每次取出最大元素,然后加上,得到真实值,算出两个新元素值,加上,两个新元素值减去,丢入堆中。

2、代码

#include <bits/stdc++.h>

#define int long long

using namespace std;

 

const int Max=7000100;

int n,m,u,v,q,t,h1=1,t1,h2=1,t2,h3=1,t3,sum,x,pre,num;

int ans[Max],q1[Max],q2[Max],q3[Max];

 

inline int get_int()

{

       int x=0,f=1;

       char c;

       for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());

      

       if(c=='-')

       {

              f=-1;c=getchar();

       }

      

       for(;isdigit(c);c=getchar())

              x=(x<<3)+(x<<1)+c-'0';

      

       return x*f;

}

 

inline void print(int x)

{

       if(x > 9)

              print(x/10);

       putchar(x%10+'0');

}

 

inline bool comp(const int &a,const int &b)

{

       return a>b;

}

 

inline int calc(int x)

{

       return x*u/v;

}

 

inline void solve()

{

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

       {

              num=max(q1[h1],max(q2[h2],q3[h3]));

              if(q1[h1]==num)

                     h1++;

              else if(q2[h2]==num)

                     h2++;

              else

                     h3++;

              x=num+sum;sum+=q;

              if(!(i%t))

                     print(x),putchar(' ');

             

              num=calc(x),pre=x-num;

              q2[++t2]=num-sum,q3[++t3]=pre-sum;

       }

}

 

signed main()

{

       n=get_int(),m=get_int(),q=get_int(),u=get_int(),v=get_int(),t=get_int();

      

       memset(q1,-0x3f3f3f,sizeof(q1)),memset(q2,-0x3f3f3f,sizeof(q2)),memset(q3,-0x3f3f3f,sizeof(q3));

      

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

              q1[i]=get_int();

       sort(q1+1,q1+n+1,comp);

       solve(),putchar('\n');

      

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

       {

              x=max(q1[h1],max(q2[h2],q3[h3]));

              if(q1[h1]==x)

                     h1++;

              else if(q2[h2]==x)

                     h2++;

              else

                     h3++;

             

              if(!(i%t))

                     print(x+sum),putchar(' ');

       }

       return 0;

}

第3题(day2):愤怒的小鸟

1、说明

A、试题类型:

       经典数学问题。

 

B、算法模型:

       抛物线。

 

C、试题说明:

       无。

 

 

2、代码

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

 

const double eps=1e-8;

 

double abs(double x)

{

       return x>0?x:-x;

}

 

bool dy(double a,double b)

{

       return abs(a-b)<eps;

}

 

int n=0,m=0,ans=0;

double x[20],y[20],ax[20],bx[20],tx[20],ty[20];

 

void dfs(int c,int u,int v)

{

       if(u+v>=ans)

              return;

      

       if(c>n)

       {

              ans=u+v;

              return;

       }

      

       bool bb=0;

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

              if(dy(ax[i]*x[c]*x[c]+bx[i]*x[c],y[c]))

              {

                     dfs(c+1,u,v);

                     bb=1;

                     break;

              }

              if(!bb)

              {

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

                     {

                            if(dy(x[c],tx[i]))

                                   continue;

                            double a=(y[c]*tx[i]-ty[i]*x[c])/(x[c]*x[c]*tx[i]-tx[i]*tx[i]*x[c]);

                            double b=(y[c]-x[c]*x[c]*a)/x[c];

                            if(a<0)

                            {  

                                   ax[u+1]=a;

                                   bx[u+1]=b;

                                   double q=tx[i],w=ty[i];

                                   for(int j=i;j<v;j++)

                                   {

                                          tx[j]=tx[j+1];

                                          ty[j]=ty[j+1];

                                   }

                                   dfs(c+1,u+1,v-1);

                                   for(int j=v;j>i;j--)

                                   {

                                          tx[j]=tx[j-1];

                                          ty[j]=ty[j-1];

                                   }

                                   tx[i]=q;

                                   ty[i]=w;

                            }

                     }

                     tx[v+1]=x[c];

                     ty[v+1]=y[c];

                     dfs(c+1,u,v+1);

              }

}

 

int main()

{

       int t;

       scanf("%d",&t);

       while(t--)

       {

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

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

                     scanf("%lf%lf",&x[i],&y[i]);

              ans=100;

              dfs(1,0,0);

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

       }

      

       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