牛客小白月赛 47 题解
牛客小白月赛47
A. 牛牛的装球游戏
标签
暴力
思路
- 显然,答案为
。 - 时间复杂度为
。
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int T;
double ans,pi=3.141592653589;
int t,h,r;
int main()
{
cin>>t;
while(t--)
{
cin>>r>>h;
int n=h/(2*r);
ans=pi*r*r*h-n*4.0*pi*r*r*r/3;
printf("%.3lf\n",ans);
}
return 0;
}
B. 牛牛的数字集合
标签
数学
思路
- 因为均值不等式
,故 即为最小价值和。 - 时间复杂度为
。
代码
点击查看代码
n=eval(input())
a=[int(e) for e in input().split()]
ans=1
for e in a:
ans=(ans*e)%(int(1e9+7))
print(ans)
C. 小猫排队
标签
双指针
思路
- 对撞指针,也可以用双端队列模拟。
- 时间复杂度为
。
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int n,a[maxn],ans;
deque<int> q;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n+1;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
q.push_back(a[i]);
while(true)
{
int del=0;
while(!q.empty()&&q.back()<=a[n+1])
del++,q.pop_back();
if(q.empty())
{
ans+=(del+1);
break;
}
q.pop_back();ans++;
if(q.empty()) break;
q.pop_front();
}
cout<<ans;
return 0;
}
D. 造桥
标签
线性 DP
思路
- 因为状态的转移与结尾字符与开头字符有关,故设状态
表示在前 个字符串中进行拼接且最后以第 个字符串作为结尾能得到的最大长度。则 。由于与第 个拼接只与前面的串的最后一个字符有关,故设 表示前 个字符中以 ascii 码为 结尾的拼接串的最大长度,同时可将 滚动数组为 。则 。 - 时间复杂度为
。
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+100;
int t,n,maxl[200],ans;
char a[maxn];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(maxl,0,sizeof(maxl));
ans=0;
for(int i=1;i<=n;i++)
{
cin>>a+1;
int len=strlen(a+1);
ans=max(ans,maxl[a[1]]+len);
maxl[a[len]]=max(maxl[a[1]]+len,maxl[a[len]]);
}
printf("%d\n",ans);
}
}
E. 牛牛的方格图
标签
二维差分
思路
- 首先证明若某一种颜色有
个不同的点,则其覆盖面为矩形,采用数学归纳法。当 时,结论显然成立。当 时,假设结论成立。则当 时,分离出一点,则可知其他 个点可形成 个矩形,进而这 个点可等效为矩形的左上顶点与右下顶点 个点,由假设,这两个点连同分离出的一点的覆盖面一定为矩形,因为 。故只需统计每种颜色的行最大值 、行最小值 、列最大值 、列最小值 ,则关于该颜色的覆盖面即为左上顶点为 、右下顶点为 的矩形。 - 考虑如何得知某一点是否被覆盖,只需判断在其上的颜色种类数是否大于
即可。因为覆盖面为矩形,故需要区间修改,单点查询,采用二维差分。 - 时间复杂度为
。
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxt=1e6+5;
const int maxn=1e3+5;
int col[maxt][4],n,m,c,ci[maxn][maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=int(1e6);i++)
col[i][1]=int(1e3+100),col[i][3]=int(1e3+100);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&c);
col[c][0]=max(col[c][0],i);
col[c][1]=min(col[c][1],i);
col[c][2]=max(col[c][2],j);
col[c][3]=min(col[c][3],j);
}
for(int i=1;i<=int(1e6);i++)
{
if(col[i][0]==0) continue;
if(col[i][0]==col[i][1]&&col[i][2]==col[i][3]) continue;
int l,r,x,y;
l=col[i][0],r=col[i][2],x=col[i][1],y=col[i][3];
ci[l+1][r+1]++,ci[l+1][y]--,ci[x][r+1]--,ci[x][y]++;
}
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
ci[i][j]+=ci[i-1][j]+ci[i][j-1]-ci[i-1][j-1];
if(ci[i][j]==0) ans++;
}
}
cout<<ans;
return 0;
}
F. 缆车
标签
最近公共祖先
思路
- 若
个点 全都可以通达,则新修的铁路可以建在 与其子树中除其以外的任意节点之间,暴力枚举子树中的节点更新最小代价即可,具体方式为 。 - 若
个点 不可全都通达,则新修的铁路不可随意安置,必须使 与其他景点可通达,显然建在不可通达点的最近公共祖先处可使代价最小。 - 时间复杂度为
。
代码
点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxlg=20;
const int maxn=2e5+100;
int depth[maxn],anc[maxn][maxlg+5],sum[maxn];
bool vis[maxn],flag[maxn];
int head[maxn],cnt;
struct edge
{
int to,next;
} e[maxn];
void add(int u,int v)
{
e[++cnt]=(edge){v,head[u]};
head[u]=cnt;
}
int n,k,m;
void dfs(int u,int fa,int d,int tp)
{
if(u==k) tp=1;
flag[u]=tp;
anc[u][0]=fa,depth[u]=d;
if(vis[u]) sum[u]=1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
dfs(v,u,d+1,tp);
sum[u]+=sum[v];
}
}
void Init()
{
for(int j=1;j<=maxlg;j++)
for(int i=1;i<=n;i++)
anc[i][j]=anc[anc[i][j-1]][j-1];
}
void swim(int &x,int h)
{
for(int i=0;h;i++)
{
if(h&1) x=anc[x][i];
h>>=1;
}
}
int lca(int x,int y)
{
if(depth[x]<depth[y]) swap(x,y);
swim(x,depth[x]-depth[y]);
if(x==y) return x;
for(int i=maxlg;anc[x][0]!=anc[y][0];i--)
if(anc[x][i]!=anc[y][i])
x=anc[x][i],y=anc[y][i];
return anc[x][0];
}
void dfsi(int u,ll &ans,ll sumi)
{
if(u!=k)
ans=min(ans,sumi-1ll*sum[u]*(depth[u]-depth[k]-1));
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
dfsi(v,ans,sumi);
}
}
int main()
{
scanf("%d",&n);
int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
}
scanf("%d%d",&m,&k);
int x;
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
vis[x]=true;
}
dfs(1,0,1,0);
Init();
int all_father=-1;
for(int i=1;i<=n;i++)
{
if(flag[i]||!vis[i]) continue;
if(all_father==-1) all_father=i;
else all_father=lca(all_father,i);
}
if(all_father!=-1)
{
ll ans=0,del;
for(int i=1;i<=n;i++)
{
if(!vis[i]) continue;
if(flag[i])
del=depth[i]-depth[k];
else del=1+depth[i]-depth[all_father];
ans+=del;
}
printf("%lld",ans);
}
else
{
ll sumi=0,ans=0;
for(int i=1;i<=n;i++)
if(vis[i]) sumi+=depth[i]-depth[k];
ans=sumi;
dfsi(k,ans,sumi);
printf("%lld",ans);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】