@Asuna
2017-04-22T14:10:02.000000Z
字数 4888
阅读 1064
题解
题意:一串01序列,两种操作,一种是从i到j取反,一种是问第i个是0还是1.
题解:线段树区间更新,单点查询。把需要翻转的区间标记,记录这个区间的翻转次数,然后向下传标记,查询时只需看看这个点翻转奇数次还是偶数次。
参考代码:
#include<iostream>#include<cstdio>#include<cstring>using namespace std;int tre[400010],lazy[400010],t,n,len,icase;char op[2],s[100010];void pushdown(int rt){//cout<<rt<<endl;if (lazy[rt]!=0){tre[rt*2]+=lazy[rt];tre[rt*2+1]+=lazy[rt];lazy[rt*2]+=lazy[rt];lazy[rt*2+1]+=lazy[rt];lazy[rt]=0;}return ;}void update(int L,int R,int l,int r,int rt){//cout<<rt<<endl;if (L<=l && r<=R){tre[rt]++;lazy[rt]++;return ;}int mid=(l+r)/2;pushdown(rt);if (L<=mid) update(L,R,l,mid,rt*2);if (mid<R) update(L,R,mid+1,r,rt*2+1);}int query(int L,int R,int l,int r,int rt){//cout<<rt<<endl;if (L==l && r==R){// cout<<tre[rt]<<endl;return tre[rt];}//cout<<L<<" "<<R<<" "<<tre[rt]<<endl;int mid=(l+r)/2,ans=0;pushdown(rt);if (L<=mid) return query(L,R,l,mid,rt*2);if (R>mid) return query(L,R,mid+1,r,rt*2+1);return ans;}int main(){scanf("%d",&t);while (t--){scanf("%s%d",s+1,&n);len=strlen(s+1);printf("Case %d:\n",++icase);memset(tre,0,sizeof(tre));memset(lazy,0,sizeof(lazy));while (n--){scanf("%s",op);if (op[0]=='I'){int l,r;scanf("%d%d",&l,&r);update(l,r,1,len,1);}else{int x,ans;scanf("%d",&x);ans=query(x,x,1,len,1);//cout<<ans<<" "<<s[x]<<endl;if (ans%2!=0){if (s[x]=='0') printf("%d\n",1);else printf("%d\n",0);}else{if (s[x]=='0') printf("%d\n",0);else printf("%d\n",1);}}}}return 0;}
题意:题意很简单,给n个有序的数,这些数分布在一个坐标轴上。给q次查找,询问在区间x,y中有多少个数据。
题解:寻找这些点中对于每条线段的上下界即可。
参考代码:
#include<iostream>#include<cstdio>#include<algorithm>using namespace std;int t,p,q,a[100010],icase;int find(int x,int y){int l=0,r=p-1,ret1=-1;while(l<=r){int mid=(l+r)/2;if(a[mid]>=x){ret1=mid;r=mid-1;}else l=mid+1;}l=0;r=p-1;int ret2=-1;while(l<=r){int mid=(l+r)/2;if(a[mid]<=y){ret2=mid;l=mid+1;}else r=mid-1;}if (ret1==-1 || ret2==-1) return 0;return ret2-ret1+1;}int main(){scanf("%d",&t);while(t--){printf("Case %d:\n",++icase);scanf("%d%d",&p,&q);for (int i=0; i<p; i++) scanf("%d",&a[i]);while (q--){int x,y;scanf("%d%d",&x,&y);printf("%d\n",find(x,y));}}return 0;}
题意:给出大圆半径,以及其内的小圆个数,求小圆的半径。
题解:大圆中心A与小圆中心B相连,之后与2小圆交点相连,得到一个垂直三角形。
参考代码:
#include<iostream>#include<cstdio>#include<cmath>using namespace std;const double PI=acos(-1.0);int main(){int cas,i,j=0,n;double R,r;scanf("%d",&cas);while(cas--){j++;scanf("%lf %d",&R,&n);printf("Case %d: ",j);r=(R*sin(PI/(n*1.0)))/(1+sin(PI/(n*1.0)));printf("%.10lf\n",r);}return 0;}
题意:有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};
参考代码:
#include<iostream>#include<cstdio>#include<queue>#include<cstring>#include<algorithm>using namespace std;int dp[1010][3],R[1010],G[1010],B[1010],ans,t,icase;int main(){scanf("%d",&t);while (t--){int n;scanf("%d",&n);for(int i=1; i<=n; i++)scanf("%d %d %d",&R[i],&G[i],&B[i]);memset(dp,0,sizeof(dp));for(int i=1; i<=n; i++){dp[i][0]=min(dp[i-1][1],dp[i-1][2])+R[i];dp[i][1]=min(dp[i-1][0],dp[i-1][2])+G[i];dp[i][2]=min(dp[i-1][0],dp[i-1][1])+B[i];}ans=min(dp[n][0],min(dp[n][1],dp[n][2]));printf("Case %d: %d\n",++icase,ans);}return 0;}
题意:给定一个数组,查询给定区间内的最小值。
题解:线段树求区间最值。。。可能学名叫RMQ?
参考代码:
#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>using namespace std;int tre[400010],t,n,m,icase;void build(int rt,int l,int r){if (l==r){scanf("%d",&tre[rt]);return;}int mid=(l+r)/2;build(rt*2,l,mid);build(rt*2+1,mid+1,r);tre[rt]=min(tre[rt*2],tre[rt*2+1]);}int query(int rt,int l,int r,int L,int R){if(l>=L && r<=R){return tre[rt];}int mid=(l+r)/2,ret=1000000000;if (mid>=L){ret=min(query(rt*2,l,mid,L,R),ret);}if (mid<R){ret=min(query(rt*2+1,mid+1,r,L,R),ret);}return ret;}int main(){scanf("%d",&t);while (t--){printf("Case %d:\n",++icase);scanf("%d%d",&n,&m);build(1,1,n);while (m--){int l,r;scanf("%d%d",&l,&r);printf("%d\n",query(1,1,n,l,r));}}return 0;}
题意:给出一棵树,n个顶点,n-1 条边,给出每条边的权值,问树上的任意两点的最大距离是多少。
题解:树上最长路?用“树的直径”做。先确定起点,随后从这个起点再次遍历整棵树,便能更新出整棵树上的最大距离了。用bfs遍历即可。
附上树的直径详解博客http://www.cnblogs.com/wuyiqi/archive/2012/04/08/2437424.html
参考代码:
#include<iostream>#include<cstdio>#include<queue>#include<cstring>#include<algorithm>using namespace std;int edgenum,head[300010],sx,ans,dist[300010],vis[300010],t,icase,n;struct node{int to,val,next;}edge[300010];void add(int u,int v,int w){node tp={v,w,head[u]};edge[edgenum]=tp;head[u]=edgenum++;}void bfs(int st){memset(dist,0,sizeof(dist));memset(vis,0,sizeof(vis));queue<int> q;q.push(st);dist[st]=0;vis[st]=1;ans=0;while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;if(!vis[v]){vis[v]=1;dist[v]=dist[u]+edge[i].val;if(ans<dist[v]){ans=dist[v];sx=v;}q.push(v);}}}}int main(){scanf("%d",&t);while(t--){edgenum=0;memset(head,-1,sizeof(head));scanf("%d",&n);for(int i=0; i<n-1; i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);add(a,b,c);add(b,a,c);}bfs(0);bfs(sx);printf("Case %d: %d\n",++icase,ans);}return 0;}