给出大神和菜鸟的人数,必须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 long
ll 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;
}
一棵树。给出两个点,问这棵树上有多少点,到这两个点的距离相等。分析一下就可以知道,如果这两个点的距离是奇数,答案肯定是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 100010
int 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;
}