NOIP2016提高组 解题报告

D1

T1 玩具谜题

 1 //朝向内的人的向左为加,向右为减;朝向内的人则相反
 2 #include<iostream>
 3 #include<cstdio>
 4 using namespace std;
 5 struct node{
 6     int dir;
 7     char name[15];
 8 }peo[100001];
 9 int n,m,now;
10 inline int qread()
11 {
12     int x=0,j=1;
13     char ch=getchar();
14     while(ch<'0' || ch>'9'){if(ch=='-')j=-1;ch=getchar();}
15     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
16     return x*j;
17 }
18 int main()
19 {
20     freopen("toy.in","r",stdin);
21     freopen("toy.ans","w",stdout);
22     scanf("%d%d",&n,&m);
23     for(int i=0;i<=n-1;i++)
24     {
25         peo[i].dir=qread();
26         scanf("%s",peo[i].name);
27     }
28     int dir,step;
29     for(int i=1;i<=m;i++)
30     {
31         dir=qread();step=qread();
32         int t=peo[now].dir+dir;
33         if(t%2==0)now=(now-step+n)%n;
34         else now=(now+step)%n;
35     }
36     cout<<peo[now].name;
37     fclose(stdin);fclose(stdout);
38     return 0;
39 }
View Code

T2 天天爱跑步

非常懵的一道题

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 const int N=300401;
  6 struct Person{
  7     int s,t,lca;
  8 }peo[N];
  9 struct node{
 10     int v,nxt;
 11 }e[N<<1];
 12 int n,m,sz,tot,cnt;
 13 int fat[N],son[N],deep[N],bl[N],id[N],ans[N];
 14 int in[N],out[N],w[N];
 15 //deep表示节点的深度,w表示观察者的出现时间 
 16 int head[N];
 17 int root[N*3],lc[N*25],rc[N*25],sum[N*25];
 18 void Insert(int u,int v)
 19 {
 20     e[++cnt].v=v;
 21     e[cnt].nxt=head[u];
 22     head[u]=cnt;
 23 }
 24 void dfs1(int now)
 25 {
 26     son[now]++;
 27     for(int i=head[now];i;i=e[i].nxt)
 28     {
 29         if(e[i].v==fat[now])continue;
 30         deep[e[i].v]=deep[now]+1;
 31         fat[e[i].v]=now;
 32         dfs1(e[i].v);
 33         son[now]+=son[e[i].v];
 34     }
 35 }
 36 void dfs2(int now,int chain)
 37 {
 38     id[now]=++sz;
 39     in[now]=sz;
 40     bl[now]=chain;
 41     int y=0;
 42     for(int i=head[now];i;i=e[i].nxt)
 43     {
 44         if(e[i].v==fat[now])continue;
 45         if(son[e[i].v]>son[y])y=e[i].v;
 46     }
 47     if(!y) 
 48     {
 49         out[now]=sz;
 50         return;
 51     }
 52     dfs2(y,chain);
 53     for(int i=head[now];i;i=e[i].nxt)
 54     {
 55         if(e[i].v==fat[now] || e[i].v==y)continue;
 56         dfs2(e[i].v,e[i].v);
 57      }
 58      out[now]=sz;
 59 }
 60 int getlca(int u,int v)
 61 {
 62     while(bl[u]!=bl[v])
 63     {
 64         if(deep[bl[u]]<deep[bl[v]])swap(u,v);
 65         u=fat[bl[u]];
 66     }
 67     return deep[u]<deep[v]?u:v;
 68 }
 69 void modify(int &now,int l,int r,int pos,int w)
 70 {
 71     if(!pos)return;
 72     if(!now)now=++tot;
 73     sum[now]+=w;
 74     if(l==r)return;
 75     int mid=l+r>>1;
 76     if(pos<=mid)modify(lc[now],l,mid,pos,w);
 77     else modify(rc[now],mid+1,r,pos,w);
 78 }
 79 int query(int now,int l,int r,int nowl,int nowr)
 80 {
 81     if(!now)return 0;
 82     if(l==nowl && r==nowr)return sum[now];
 83     int mid=l+r>>1;
 84     if(nowr<=mid)return query(lc[now],l,mid,nowl,nowr);
 85     else if(nowl>mid)return query(rc[now],mid+1,r,nowl,nowr);
 86     else return query(lc[now],l,mid,nowl,mid)+query(rc[now],mid+1,r,mid+1,nowr);
 87 }
 88 void clear()
 89 {
 90     tot=0;
 91     memset(lc,0,sizeof(lc));
 92     memset(rc,0,sizeof(rc));
 93     memset(sum,0,sizeof(sum));
 94     memset(root,0,sizeof(root));
 95 }
 96 int main()
 97 {
 98     scanf("%d%d",&n,&m);
 99     int u,v;
100     for(int i=1;i<n;i++)
101     {
102         scanf("%d%d",&u,&v);
103         Insert(u,v);Insert(v,u);
104     }
105     for(int i=1;i<=n;i++)
106         scanf("%d",&w[i]);
107     for(int i=1;i<=m;i++)
108         scanf("%d%d",&peo[i].s,&peo[i].t);
109     dfs1(1);
110     dfs2(1,0);
111     for(int i=1;i<=m;i++)
112         peo[i].lca=getlca(peo[i].s,peo[i].t);
113     int now;
114     for(int i=1;i<=m;i++)
115     {
116         now=deep[peo[i].s];
117         modify(root[now],1,n,id[peo[i].s],1);
118         modify(root[now],1,n,id[fat[peo[i].lca]],-1);
119     }
120     for(int i=1;i<=n;i++)
121         ans[i]=query(root[deep[i]+w[i]],1,n,in[i],out[i]);
122     clear();
123     for(int i=1;i<=m;i++)
124     {
125         now=deep[peo[i].s]-deep[peo[i].lca]*2+n*2;
126         modify(root[now],1,n,id[peo[i].t],1);
127         modify(root[now],1,n,id[peo[i].lca],-1);
128     }
129     for(int i=1;i<=n;i++)
130         ans[i]+=query(root[w[i]-deep[i]+n*2],1,n,in[i],out[i]);
131     for(int i=1;i<=n;i++)
132         printf("%d ",ans[i]);
133     return 0;
134 }
View Code

T3 换教室

Floyd+期望dp
 1 /*1.当前的课不换的情况:
 2 (1)上一节课也没换;
 3 (2)上一节课换了----成功or不成功;
 4 2.当前的课换的情况:
 5 (1)当前课成功换了:
 6 a.上一节课换了----上一节课成功or不成功;
 7 b.上一节课没换;
 8 (2)当前的课换了失败:
 9 a.上一节课换了----上一节课成功or不成功;
10 b.上一节课没换*/
11 #include<iostream>
12 #include<cstdio>
13 #include<cstring>
14 using namespace std;
15 const int N=2001;
16 const int INF=1e9+7;
17 int n,m,v,e;
18 int c[N],d[N],dis[301][301];
19 double k[N],f[N][N][2];
20 //f[i][j][k]表示当前在第i个时间段,申请了j个教室,k==0表示申请不通过,k==1表示申请通过,最小耗费体力的期望值 
21 inline int qread()
22 {
23     int x=0,j=1;
24     char ch=getchar();
25     while(ch<'0' || ch>'9'){if(ch=='-')j=-1;ch=getchar();}
26     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
27     return x*j;
28 }
29 void init()
30 {
31     for(int i=0;i<301;i++)
32         for(int j=0;j<301;j++)
33             if(i==j)
34                 dis[i][j]=0;
35             else dis[i][j]=INF;
36     for (int i=0;i<2001;i++)
37         for (int j=0;j<2001;j++)
38             f[i][j][0]=f[i][j][1]=INF;
39     f[1][0][0]=0;
40     f[1][1][1]=0;
41 }
42 void floyd()
43 {
44     for(int k=1;k<=v;k++)
45         for(int i=1;i<=v;i++)
46             for(int j=1;j<=v;j++)
47                 if(dis[i][j]>dis[i][k]+dis[k][j])
48                     dis[i][j]=dis[i][k]+dis[k][j];
49 }
50 int main()
51 {
52     freopen("classroom.in","r",stdin);
53     freopen("classroom.ans","w",stdout);
54     init();
55     scanf("%d%d%d%d",&n,&m,&v,&e);
56     for(int i=1;i<=n;i++)
57         c[i]=qread();
58     for(int i=1;i<=n;i++)
59         d[i]=qread();
60     for(int i=1;i<=n;i++)
61         scanf("%lf",&k[i]);
62     for(int i=1;i<=e;i++)
63     {
64         int u=qread(),v=qread(),w=qread();
65         if(w<dis[u][v])
66             dis[u][v]=dis[v][u]=w;
67     }
68     floyd();
69     for(int i=2;i<=n;i++)
70     {
71         f[i][0][0]=f[i-1][0][0]+dis[c[i-1]][c[i]];
72         for(int j=1;j<=min(i,m);j++)
73         {
74             f[i][j][0]=min(f[i-1][j][0]+dis[c[i-1]][c[i]],
75                 f[i-1][j][1]+(1-k[i-1])*dis[c[i-1]][c[i]]+k[i-1]*dis[d[i-1]][c[i]]);
76             f[i][j][1]=min(f[i-1][j-1][0]+k[i]*dis[c[i-1]][d[i]]+(1-k[i])*dis[c[i-1]][c[i]],
77                 f[i-1][j-1][1]+k[i-1]*k[i]*dis[d[i-1]][d[i]]+(1-k[i-1])*k[i]*dis[c[i-1]][d[i]]
78                 +k[i-1]*(1-k[i])*dis[d[i-1]][c[i]]+(1-k[i-1])*(1-k[i])*dis[c[i-1]][c[i]]);
79         }
80     }
81     double ans=f[n][0][0];
82     for(int i=1;i<=m;i++)
83         ans=min(ans,min(f[n][i][0],f[n][i][1]));
84     printf("%.2lf
",ans);
85     fclose(stdin);fclose(stdout);
86     return 0;
87 }
View Code

D2

T1 组合数问题

先写几组小数据发现是杨辉三角,那么与处理处杨辉三角的值,再用矩阵前缀和维护答案,最后O(1)查询答案。

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int n,m,t,k,tot;
 5 int f[2011][2011],ans[2017][2017];
 6 inline int qread()
 7 {
 8     int x=0,j=1;
 9     char ch=getchar();
10     while(ch<'0' || ch>'9'){if(ch=='-')j=-1;ch=getchar();}
11     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
12     return x*j;
13 }
14 int main()
15 {
16 //    freopen("problem.in","r",stdin);
17 //    freopen("problem.out","w",stdout);
18     scanf("%d%d",&t,&k);
19     f[1][1]=1;
20     for(int i=2;i<=2000;i++)
21         for(int j=1;j<=i;j++)
22             f[i][j]=(f[i-1][j-1]+f[i-1][j])%k;
23     for(int i=1;i<=2000;i++)
24     {
25         for(int j=1;j<i;j++)
26             ans[i][j]=ans[i][j-1]+ans[i-1][j]-ans[i-1][j-1]+(f[i][j]==0);
27         ans[i][i]=ans[i][i-1];
28     }
29     while(t--)
30     {
31         n=qread();m=qread();
32         if(m>n)m=n;
33         printf("%d
",ans[n+1][m+1]);
34     }
35     fclose(stdin);fclose(stdout);
36     return 0;
37 }
View Code

T2 蚯蚓

 1 /*
 2 搞三个队列 
 3 将蚯蚓从大到小放到第一个队列里 
 4 每一次砍3个队列中队首最大的蚯蚓 
 5 然后计算出来和之后分别将这两个蚯蚓放到第2个和第3个队列里 
 6 可以发现这样的话这三个队列都是分别单调的 
 7 由于每一次其余的蚯蚓都要+tot,那么就将新得到的两个蚯蚓-tot之后再加入队列就可以了 
 8 */
 9 #include<iostream>
10 #include<cstdio>
11 #include<cmath>
12 #include<algorithm>
13 using namespace std;
14 const int INF=0x7fffffff;
15 int n,m,tot,u,v,t,add,k,now;
16 long long a[100001],q[4][10000005],head[4],tail[4];
17 inline int qread()
18 {
19     int x=0,j=1;
20     char ch=getchar();
21     while(ch<'0' || ch>'9'){if(ch=='-')j=-1;ch=getchar();}
22     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
23     return x*j;
24 }
25 int main()
26 {
27     //freopen("earthworm.in","r",stdin);
28     //freopen("earthworm.out","w",stdout);
29     scanf("%d%d%d%d%d%d",&n,&m,&tot,&u,&v,&t);
30     head[1]=head[2]=head[3]=1;
31     for(int i=1;i<=n;i++)
32         a[i]=qread();
33     sort(a+1,a+n+1);
34     for(int i=n;i>=1;i--)
35         q[1][++tail[1]]=a[i];
36     for(int i=1;i<=m;i++)
37     {
38         now=-INF;
39         for(int j=1;j<=3;j++)
40             if(head[j]<=tail[j] && q[j][head[j]]>now)
41             {
42                 now=q[j][head[j]];
43                 k=j;
44             }
45         now+=add;
46         if(i%t==0)
47             printf("%d ",now);
48         int nxt1=(long long)now*u/v,nxt2=now-nxt1;
49         add+=tot;
50         q[2][++tail[2]]=nxt1-add;
51         q[3][++tail[3]]=nxt2-add;
52         head[k]++;
53     }
54     putchar('
');
55     for(int i=1;i<=n+m;i++)
56     {
57         now=-INF;
58         for(int j=1;j<=3;j++)
59             if(head[j]<=tail[j] && q[j][head[j]]>now)
60             {
61                 now=q[j][head[j]];
62                 k=j;
63             }
64         now+=add;
65         if(i%t==0)
66             printf("%d ",now);
67         head[k]++;
68     }
69     fclose(stdin);fclose(stdout);
70     return 0;
71 }
View Code

T3 愤怒的小鸟

 1 /*
 2 状压dp
 3 预处理一个数组canshe[i][j]表示连接i,j两点做抛物线的时候能打到的小猪
 4 特别的,canshe[i][i]只能打到自己,能打到的小猪分别是谁这个用二进制表示
 5 然后进行dp
 6 f[i|canshe[j][k]]=min(f[i|canshe[j][k]],f[i]+1)
 7 但是这样只能得85分
 8 需要优化一下 
 9 当(i&(1<<(j-1))时,也就是说枚举的小猪之前打过,那么这种枚举之前以一定枚举过
10 所以我们只需要加上一个if(!(i&(1<<(j-1))))特判就能过 
11 */
12 #include<iostream>
13 #include<cstdio>
14 #include<algorithm>
15 #include<cstring>
16 using namespace std;
17 const double eps=1e-8;
18 struct node{
19     double x,y;
20 }pig[19];
21 int canshe[19][19];//用二进制表示  连接这两个点的抛物线能够打掉哪些点 
22 int f[1<<19];//表示打掉二进制位的当前状态的小鸟的最少花费 
23 int t,n,m; 
24 double a,b;
25 void calc(int x,int y)
26 {
27     double xa=pig[x].x,ya=pig[x].y,xb=pig[y].x,yb=pig[y].y;
28     double xaa=xa*xa,xbb=xb*xb;
29     double op=xb/xa;
30     xaa*=op;
31     xa*=op;
32     ya*=op;
33     a=(ya-yb)/(xaa-xbb);
34     b=(yb-a*xbb)/xb;
35 }
36 int main()
37 {
38     freopen("angrybirds.in","r",stdin);
39     freopen("angrybirds.out","w",stdout);
40     scanf("%d",&t);
41     while(t--)
42     {
43         scanf("%d%d",&n,&m);
44         memset(canshe,0,sizeof(canshe));
45         memset(f,0x3e,sizeof(f));
46         f[0]=0;
47         for(int i=1;i<=n;i++)
48             scanf("%lf%lf",&pig[i].x,&pig[i].y);
49         for(int i=1;i<=n;i++)
50         {
51             canshe[i][i]=1<<(i-1);
52             for(int j=i+1;j<=n;j++)
53             {
54                 calc(i,j);
55                 if(a>0)continue;
56                 for(int k=1;k<=n;k++)
57                 {
58                     double ans=pig[k].x*a*pig[k].x+pig[k].x*b;
59                     double tmp=ans-pig[k].y;
60                     if(tmp<0)tmp=-tmp;
61                     if(tmp<=eps)
62                         canshe[i][j]|=(1<<(k-1));
63                 }
64             }
65         }
66         for(int i=0;i<=(1<<n)-1;i++)
67             for(int j=1;j<=n;j++)
68                 if(i&(1<<(j-1))==0)
69                     for(int k=j;k<=n;k++)
70                         f[i|canshe[j][k]]=min(f[i|canshe[j][k]],f[i]+1);
71         printf("%d
",f[(1<<n)-1]);
72     }
73     fclose(stdin);fclose(stdout);
74     return 0;
75 }
View Code
原文地址:https://www.cnblogs.com/1078713946t/p/7661558.html