[关闭]
@Asuna 2017-04-22T14:10:02.000000Z 字数 4888 阅读 775

CQUPT 训练题题解 2017/4/10

题解


Problem A:Binary Simulation

题意:一串01序列,两种操作,一种是从i到j取反,一种是问第i个是0还是1.

题解:线段树区间更新,单点查询。把需要翻转的区间标记,记录这个区间的翻转次数,然后向下传标记,查询时只需看看这个点翻转奇数次还是偶数次。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. int tre[400010],lazy[400010],t,n,len,icase;
  6. char op[2],s[100010];
  7. void pushdown(int rt)
  8. {
  9. //cout<<rt<<endl;
  10. if (lazy[rt]!=0)
  11. {
  12. tre[rt*2]+=lazy[rt];
  13. tre[rt*2+1]+=lazy[rt];
  14. lazy[rt*2]+=lazy[rt];
  15. lazy[rt*2+1]+=lazy[rt];
  16. lazy[rt]=0;
  17. }
  18. return ;
  19. }
  20. void update(int L,int R,int l,int r,int rt)
  21. {
  22. //cout<<rt<<endl;
  23. if (L<=l && r<=R)
  24. {
  25. tre[rt]++;
  26. lazy[rt]++;
  27. return ;
  28. }
  29. int mid=(l+r)/2;
  30. pushdown(rt);
  31. if (L<=mid) update(L,R,l,mid,rt*2);
  32. if (mid<R) update(L,R,mid+1,r,rt*2+1);
  33. }
  34. int query(int L,int R,int l,int r,int rt)
  35. {
  36. //cout<<rt<<endl;
  37. if (L==l && r==R)
  38. {
  39. // cout<<tre[rt]<<endl;
  40. return tre[rt];
  41. }
  42. //cout<<L<<" "<<R<<" "<<tre[rt]<<endl;
  43. int mid=(l+r)/2,ans=0;
  44. pushdown(rt);
  45. if (L<=mid) return query(L,R,l,mid,rt*2);
  46. if (R>mid) return query(L,R,mid+1,r,rt*2+1);
  47. return ans;
  48. }
  49. int main()
  50. {
  51. scanf("%d",&t);
  52. while (t--)
  53. {
  54. scanf("%s%d",s+1,&n);
  55. len=strlen(s+1);
  56. printf("Case %d:\n",++icase);
  57. memset(tre,0,sizeof(tre));
  58. memset(lazy,0,sizeof(lazy));
  59. while (n--)
  60. {
  61. scanf("%s",op);
  62. if (op[0]=='I')
  63. {
  64. int l,r;
  65. scanf("%d%d",&l,&r);
  66. update(l,r,1,len,1);
  67. }
  68. else
  69. {
  70. int x,ans;
  71. scanf("%d",&x);
  72. ans=query(x,x,1,len,1);
  73. //cout<<ans<<" "<<s[x]<<endl;
  74. if (ans%2!=0)
  75. {
  76. if (s[x]=='0') printf("%d\n",1);
  77. else printf("%d\n",0);
  78. }
  79. else
  80. {
  81. if (s[x]=='0') printf("%d\n",0);
  82. else printf("%d\n",1);
  83. }
  84. }
  85. }
  86. }
  87. return 0;
  88. }

Problem B:Points in Segments

题意:题意很简单,给n个有序的数,这些数分布在一个坐标轴上。给q次查找,询问在区间x,y中有多少个数据。

题解:寻找这些点中对于每条线段的上下界即可。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. using namespace std;
  5. int t,p,q,a[100010],icase;
  6. int find(int x,int y)
  7. {
  8. int l=0,r=p-1,ret1=-1;
  9. while(l<=r)
  10. {
  11. int mid=(l+r)/2;
  12. if(a[mid]>=x)
  13. {
  14. ret1=mid;
  15. r=mid-1;
  16. }
  17. else l=mid+1;
  18. }
  19. l=0;
  20. r=p-1;
  21. int ret2=-1;
  22. while(l<=r)
  23. {
  24. int mid=(l+r)/2;
  25. if(a[mid]<=y)
  26. {
  27. ret2=mid;
  28. l=mid+1;
  29. }
  30. else r=mid-1;
  31. }
  32. if (ret1==-1 || ret2==-1) return 0;
  33. return ret2-ret1+1;
  34. }
  35. int main()
  36. {
  37. scanf("%d",&t);
  38. while(t--)
  39. {
  40. printf("Case %d:\n",++icase);
  41. scanf("%d%d",&p,&q);
  42. for (int i=0; i<p; i++) scanf("%d",&a[i]);
  43. while (q--)
  44. {
  45. int x,y;
  46. scanf("%d%d",&x,&y);
  47. printf("%d\n",find(x,y));
  48. }
  49. }
  50. return 0;
  51. }

Problem C:Calm Down

题意:给出大圆半径,以及其内的小圆个数,求小圆的半径。

题解:大圆中心A与小圆中心B相连,之后与2小圆交点相连,得到一个垂直三角形。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. using namespace std;
  5. const double PI=acos(-1.0);
  6. int main()
  7. {
  8. int cas,i,j=0,n;
  9. double R,r;
  10. scanf("%d",&cas);
  11. while(cas--)
  12. {
  13. j++;
  14. scanf("%lf %d",&R,&n);
  15. printf("Case %d: ",j);
  16. r=(R*sin(PI/(n*1.0)))/(1+sin(PI/(n*1.0)));
  17. printf("%.10lf\n",r);
  18. }
  19. return 0;
  20. }

Problem D: Neighbor House

题意:有n个房子,每个房子都可以染红绿蓝三种颜色,并且给出了每个房子染每种颜色费用,相邻房子不能同色,求染完房子的最小费用。

题解:定义dp[i][j]为粉刷第i个房子用的颜色j。
转移方程:dp[i][j]=min(dp[i-1][(j+1)%3] , dp[i-1][(j+2)%3]);
一共有三种颜色{0,1,2},任取一种颜色{j},那么和颜色j不同的颜色就为{(j+1)%3,(j+2)%3};

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<queue>
  4. #include<cstring>
  5. #include<algorithm>
  6. using namespace std;
  7. int dp[1010][3],R[1010],G[1010],B[1010],ans,t,icase;
  8. int main()
  9. {
  10. scanf("%d",&t);
  11. while (t--)
  12. {
  13. int n;
  14. scanf("%d",&n);
  15. for(int i=1; i<=n; i++)
  16. scanf("%d %d %d",&R[i],&G[i],&B[i]);
  17. memset(dp,0,sizeof(dp));
  18. for(int i=1; i<=n; i++)
  19. {
  20. dp[i][0]=min(dp[i-1][1],dp[i-1][2])+R[i];
  21. dp[i][1]=min(dp[i-1][0],dp[i-1][2])+G[i];
  22. dp[i][2]=min(dp[i-1][0],dp[i-1][1])+B[i];
  23. }
  24. ans=min(dp[n][0],min(dp[n][1],dp[n][2]));
  25. printf("Case %d: %d\n",++icase,ans);
  26. }
  27. return 0;
  28. }

Problem E:Array Queries

题意:给定一个数组,查询给定区间内的最小值。

题解:线段树求区间最值。。。可能学名叫RMQ?

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cmath>
  5. using namespace std;
  6. int tre[400010],t,n,m,icase;
  7. void build(int rt,int l,int r)
  8. {
  9. if (l==r)
  10. {
  11. scanf("%d",&tre[rt]);
  12. return;
  13. }
  14. int mid=(l+r)/2;
  15. build(rt*2,l,mid);
  16. build(rt*2+1,mid+1,r);
  17. tre[rt]=min(tre[rt*2],tre[rt*2+1]);
  18. }
  19. int query(int rt,int l,int r,int L,int R)
  20. {
  21. if(l>=L && r<=R)
  22. {
  23. return tre[rt];
  24. }
  25. int mid=(l+r)/2,ret=1000000000;
  26. if (mid>=L)
  27. {
  28. ret=min(query(rt*2,l,mid,L,R),ret);
  29. }
  30. if (mid<R)
  31. {
  32. ret=min(query(rt*2+1,mid+1,r,L,R),ret);
  33. }
  34. return ret;
  35. }
  36. int main()
  37. {
  38. scanf("%d",&t);
  39. while (t--)
  40. {
  41. printf("Case %d:\n",++icase);
  42. scanf("%d%d",&n,&m);
  43. build(1,1,n);
  44. while (m--)
  45. {
  46. int l,r;
  47. scanf("%d%d",&l,&r);
  48. printf("%d\n",query(1,1,n,l,r));
  49. }
  50. }
  51. return 0;
  52. }

Problem F:Farthest Nodes in a Tree

题意:给出一棵树,n个顶点,n-1 条边,给出每条边的权值,问树上的任意两点的最大距离是多少。

题解:树上最长路?用“树的直径”做。先确定起点,随后从这个起点再次遍历整棵树,便能更新出整棵树上的最大距离了。用bfs遍历即可。
附上树的直径详解博客http://www.cnblogs.com/wuyiqi/archive/2012/04/08/2437424.html

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<queue>
  4. #include<cstring>
  5. #include<algorithm>
  6. using namespace std;
  7. int edgenum,head[300010],sx,ans,dist[300010],vis[300010],t,icase,n;
  8. struct node
  9. {
  10. int to,val,next;
  11. }edge[300010];
  12. void add(int u,int v,int w)
  13. {
  14. node tp={v,w,head[u]};
  15. edge[edgenum]=tp;
  16. head[u]=edgenum++;
  17. }
  18. void bfs(int st)
  19. {
  20. memset(dist,0,sizeof(dist));
  21. memset(vis,0,sizeof(vis));
  22. queue<int> q;
  23. q.push(st);
  24. dist[st]=0;
  25. vis[st]=1;
  26. ans=0;
  27. while(!q.empty())
  28. {
  29. int u=q.front();
  30. q.pop();
  31. for(int i=head[u];i!=-1;i=edge[i].next)
  32. {
  33. int v=edge[i].to;
  34. if(!vis[v])
  35. {
  36. vis[v]=1;
  37. dist[v]=dist[u]+edge[i].val;
  38. if(ans<dist[v])
  39. {
  40. ans=dist[v];
  41. sx=v;
  42. }
  43. q.push(v);
  44. }
  45. }
  46. }
  47. }
  48. int main()
  49. {
  50. scanf("%d",&t);
  51. while(t--)
  52. {
  53. edgenum=0;
  54. memset(head,-1,sizeof(head));
  55. scanf("%d",&n);
  56. for(int i=0; i<n-1; i++)
  57. {
  58. int a,b,c;
  59. scanf("%d%d%d",&a,&b,&c);
  60. add(a,b,c);add(b,a,c);
  61. }
  62. bfs(0);
  63. bfs(sx);
  64. printf("Case %d: %d\n",++icase,ans);
  65. }
  66. return 0;
  67. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注