A.给你一张n个点n-1条边的图,和k个关键点。求一个点到所有关键点距离最大值的最小为多少。
乍一看像是对答案二分,但是考虑两个相距最远的关键点,假设他们的距离为d,那么答案肯定为(d+1)/2
如果有一点到中心点的距离超过了(d+1)/2 ,那么这个点会成为最远关键点对中的一个。矛盾。
所以题目就变成了如何求最远的两个关键点的距离。
考虑如何求树的直径,首先取一个根节点通过bfs找到离他最远的叶子节点p,然后将p当做根节点再跑一遍bfs
求出离这个点最远的叶子节点q,那么从p到q的这条路径就是树的直径。
那么两个最远的关键点的距离就相当求出将关键点当成叶子节点的一棵树的直径,我们取一个点当根节点然后
bfs找到离他最远的关键点p 以这个关键点p为根节点再跑一遍bfs求出离这个关键点最远的关键点q,则p到q的路
径就是我们要找关键点最远距离d 然后 ans=(d+1)/2更新答案
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,k;
vector<int>g[maxn];
int vis[maxn],flag[maxn],dis[maxn];
int bfs(int x)
{
int ans;
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
queue<int>q;
q.push(x);
vis[x]=1;
dis[x]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!vis[v])
{
dis[v]=dis[u]+1;
if(flag[v])ans=v;
vis[v]=1;
q.push(v);
}
}
}
return ans;
}
int main()
{
cin>>n>>k;
int u,v;
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
int y;
for(int i=1;i<=k;i++)
{
scanf("%d",&y);
flag[y]=1;
}
int s,t;
s=bfs(1);
t=bfs(s);
cout<<(dis[t]+1)/2<<endl;
return 0;
}
K 给你一个字符串 ,求所有是300的倍数的子串。
首先考虑是3的倍数,要求一个区间是三的倍数则将他的数位前缀和%3 出现重复的时候,则区间l+1~r是3的倍数
则我们要求的区间s[r],s[r-1]均为0的时候,统计0~r-2中有多少满足sx=0,1,2在s[r-1]更新答案,
类比于30的倍数应该当s[r]=0时 在s[r]更新答案。
3000的倍数应该当s[r]=0,s[r-1]=0,s[r-2]=0时在s[r-2]更新答案。
特别 0 也是300的倍数所以每次遇到一个0 ,ans++;
#include<bits/stdc++.h>
#define ll long long
using namespace std;
char s[100016];
int x[100016];
ll mp[6];
ll ans=0;
int main()
{
scanf("%s",s+1);
int len=strlen(s+1);
mp[0]=1;
for(int i=1;i<=len;i++)
{
x[i]=((s[i]-'0')+x[i-1])%3;
if(s[i]=='0')ans++;
if(s[i]=='0'&&s[i+1]=='0')
{
ans+=mp[x[i]];
//ans++;
}
mp[x[i]]++;
}
cout<<ans<<endl;
return 0;
}