Codeforces Round #294 (Div. 2) (C D E)

来源:互联网 发布:js是什么文件 编辑:程序博客网 时间:2024/06/11 23:53

C A and B and Team Training

        给出大神和菜鸟的人数,必须1:2或者2:1组队,问最多组几队。如果n的2倍小于等于m,答案就是n,反过来也一样。否则答案是它们的和除以3,忽略余数。

#include <iostream>    #include <stdio.h>    #include <string>    #include <map>    #include <vector>    #include <stack>    #include <queue>    #include <string.h>    #include <algorithm>    #include <math.h>        using namespace std;    int main(){int n,m;cin>>n>>m;if(n*2<=m){cout<<n<<endl;}else if(m*2<=n){cout<<m<<endl;}else{cout<<(n+m)/3<<endl;}return 0;}


D A and B and Interesting Substrings

        给出26个小写字母的权和一个串,问这个串有多少这样的字串,满足头尾相同,且夹在中间的字符权值的和为0。为了迅速算出某一段的权值,计算前缀和就可以了。做法扫一遍,用map保存和查询前缀和。如果遇到同字母且前缀和相等,就是满足要求的。注意会爆int。

#include <iostream>    #include <stdio.h>    #include <string>    #include <map>    #include <vector>    #include <stack>    #include <queue>    #include <string.h>    #include <algorithm>    #include <math.h>        using namespace std;    #define ll long longll x[26];char str[100010];ll sum;map<ll,ll> mp[26];int main(){for(int i=0;i<26;i++)cin>>x[i];scanf("%s",str+1);int len=strlen(str+1);ll ans=0;for(int i=1;i<=len;i++){ans+=mp[str[i]-'a'][sum];sum+=x[str[i]-'a'];mp[str[i]-'a'][sum]++;}cout<<ans<<endl;return 0;}


E A and B and Lecture Rooms

        一棵树。给出两个点,问这棵树上有多少点,到这两个点的距离相等。分析一下就可以知道,如果这两个点的距离是奇数,答案肯定是0。如果距离为偶数,答案就是这两个点的中点,砍掉往这两个点方向的边以后树上剩下的点的个数。解题的关键在于如何迅速得到两个点的距离,这里做法是转为有根树,通过倍增算法求LCA,同时得到深度和子树大小等信息即可计算出来。

        拿到询问的两个点x,y后,分为下面几种情况。

1.它们是同一个点,显然答案为n。

2.它们深度一样,那么x,y的中点就是它们的LCA,只用砍掉两个方向的边就可以了(用倍增算法迅速找到需要砍的子树)。

3.它们深度不一样,首先计算出中点(肯定在较深的一侧,假设为x),然后在中点为根的子树上砍掉x方向的边就可以了(同样用倍增找)。

#include <iostream>#include <stdio.h>#include <vector>#include <memory.h>using namespace std;#define max_size 100010int d[max_size],p[max_size][18];int head[max_size];int cnt;struct Edge{int v;int pre;}eg[max_size];void add(int x,int y){eg[cnt].v=y;eg[cnt].pre=head[x];head[x]=cnt++;}void dfs(int k){if(head[k]==0)return;int m,x,i,j;for(i=head[k];i!=0;i=eg[i].pre){x=eg[i].v;p[x][0]=k;m=k;d[x]=d[k]+1;for(j=0;p[m][j]!=0;j++){p[x][j+1]=p[m][j];//利用公式p[x][j]=p[p[x][j-1]][j-1],这里的m就是p[x][j-1];m=p[m][j];}dfs(x);}}int find_lca(int x,int y){int m,k;if(x==y)return x;if(d[x]<d[y]){m=x;x=y;y=m;}m=d[x]-d[y];k=0;while(m){//将x的深度调到和y的深度一样if(m&1)x=p[x][k];m>>=1;k++;}if(x==y)return x;k=0;//向上调节,找最近公共祖先,算法的核心,相当于一个二分查找。while(x!=y){if(p[x][k]!=p[y][k]||p[x][k]==p[y][k]&&k==0)//如果p[x][k]还不相等,说明节点p[x][k]还在所求点的下面,所以继续向上调节//如果相等了,并且就是他们父节点,则那个节点一定就是所求点。{x=p[x][k];y=p[y][k];k++;}else//如果p[x][k]=p[y][k],可以说明p[x][k]一定是x和y的共祖先,但不一定是最近的。//所以向下找看还有没有更近的公共祖先{k--;}}return x;}vector<int> E[max_size];bool vis[max_size];int siz[max_size];int predfs(int u){vis[u]=1;int sz=E[u].size();siz[u]=1;for(int i=0;i<sz;i++){int v=E[u][i];if(!vis[v]){add(u,v);siz[u]+=predfs(v);}}return siz[u];}int find_ancestor(int u,int dis){int k=0;while(dis){if(dis&1){u=p[u][k];}dis>>=1;k++;}return u;}int main(){cnt=1;int n,m,u,v,ans;cin>>n;for(int i=1;i<n;i++){scanf("%d%d",&u,&v);E[u].push_back(v);E[v].push_back(u);}predfs(1);dfs(1);cin>>m;while(m--){scanf("%d%d",&u,&v);int LCA=find_lca(u,v);if(d[u]<d[v])swap(u,v);if(u==v){//同一个点 ans=n;}else{int dis=d[u]+d[v]-2*d[LCA];if(dis&1){ans=0;}else{//深度一样 if(d[u]==d[v]){int cutu=find_ancestor(u,dis/2-1);int cutv=find_ancestor(v,dis/2-1);ans=n-siz[cutu]-siz[cutv];}else{//深度不一样 int an=find_ancestor(u,dis/2);int cut=find_ancestor(u,dis/2-1);ans=siz[an]-siz[cut];}}}printf("%d\n",ans);}return 0;}


0 0
原创粉丝点击