20241021比赛总结
T1 岛屿
https://www.gxyzoj.com/d/hzoj/p/4177
显然每个点只增加了一条边,最终每个点的度数都为2,所以最终必然是很多个环,连边的过程中,也必然是一些链和一些环
由题,蓝同色链的个数和红同色链的个数相等,所以设
考虑先处理异色链:
红红连红蓝为红红,异色链-1,即
蓝蓝连红蓝为蓝蓝,异色链-1,即
红蓝连红蓝为红蓝(不是自己),异色链-1,即
红蓝连自己,此时构成环,联通快数量+1,即
剩余的同色链相连为红蓝,即
所以:
既:
代码:
#include<cstdio>
using namespace std;
int x,y,n;
double ans;
int main()
{
freopen("island.in","r",stdin);
freopen("island.out","w",stdout);
scanf("%d%d",&x,&y);
n=2*x+y;
for(int i=1;i<=y;i++)
{
ans+=1.0/(1.0*(2*x+i));
}
for(int i=1;i<=x;i++)
{
ans+=1.0/(1.0*(i*2-1));
}
printf("%.10lf",ans);
return 0;
}
T2 最短路
https://www.gxyzoj.com/d/hzoj/p/4178
可以先求出1到所有点的最短路长度,然后建最短路树,即让树上所有点到根的距离就是他到1的最短路
此时,去掉最后一条边就是取掉边
如图,考虑边
可以发现,因为是无向边,所以u,v,k,1在一个环上,考虑
所以可以树剖+线段树
考虑优化,因为
#include<cstdio>
#include<queue>
#include<algorithm>
#define ll long long
using namespace std;
int n,m,head[100005],edgenum;
int f[100005][19],dep[100005];
ll dis[100005],ans[100005];
int pre[100005];
struct edge{
int to,nxt;
ll val;
}e[400005];
struct Edge{
int u,v;
ll val;
}a[200005];
struct node{
int x,pre;
ll val;
bool operator < (const node &x)const{
return val>x.val;
}
};
priority_queue<node> q;
bool cmp(Edge x,Edge y)
{
return x.val<y.val;
}
void add_edge(int u,int v,ll w)
{
e[++edgenum].nxt=head[u];
e[edgenum].to=v;
e[edgenum].val=w;
head[u]=edgenum;
}
void dijkstra()
{
q.push((node){1,1,0});
while(!q.empty())
{
int u=q.top().x,p=q.top().pre;
ll val=q.top().val;
q.pop();
if(!pre[u])
{
pre[u]=p,dis[u]=val;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(!pre[v])
{
q.push((node){v,u,val+e[i].val});
}
}
}
}
}
void dfs(int u,int fa)
{
dep[u]=dep[fa]+1;
f[u][0]=fa;
for(int i=1;i<=18;i++)
{
f[u][i]=f[f[u][i-1]][i-1];
}
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa) continue;
dfs(v,u);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=18;i>=0;i--)
{
if(dep[f[x][i]]>=dep[y])
{
x=f[x][i];
}
if(x==y) return x;
}
for(int i=18;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int fa[100005];
int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void solve(int u,int ed,ll val)
{
while(dep[u]>dep[ed])
{
if(u==ed) return;
u=find(u);
if(dep[u]<=dep[ed]) return;
ans[u]=val;
fa[u]=find(ed);
u=pre[u];
}
}
int main()
{
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
a[i]=(Edge){u,v,w};
}
dijkstra();
// printf("1");
for(int i=1;i<=n;i++) head[i]=0,fa[i]=i;
edgenum=0;
for(int i=2;i<=n;i++)
{
add_edge(i,pre[i],dis[i]-dis[pre[i]]);
add_edge(pre[i],i,dis[i]-dis[pre[i]]);
}
dfs(1,0);
for(int i=1;i<=m;i++)
{
int lc=lca(a[i].u,a[i].v);
if(lc==a[i].u||a[i].v==lc)
{
for(int j=head[a[i].u];j;j=e[j].nxt)
{
if(a[i].v==e[j].to&&a[i].val==e[j].val)
{
a[i].val=1e18;
}
}
}
}
for(int i=1;i<=m;i++)
{
a[i].val+=dis[a[i].u]+dis[a[i].v];
}
sort(a+1,a+m+1,cmp);
for(int i=1;i<=m;i++)
{
int lc=lca(a[i].u,a[i].v);
// printf("%d %d %d\n",a[i].u,a[i].v,lc);
if(a[i].val>=1e18) continue;
solve(a[i].u,lc,a[i].val);
solve(a[i].v,lc,a[i].val);
}
for(int i=2;i<=n;i++)
{
if(ans[i]==0) printf("-1\n");
else printf("%lld\n",ans[i]-dis[i]);
}
return 0;
}
T3 列表
https://www.gxyzoj.com/d/hzoj/p/4179
部分分记得return 0,注意部分分的范围,不要忘了等于的情况
显然有如下性质:
性质1:对于区间
性质2:对于区间
将原序列沿
4 7 3 6
5 2 1
计算每一列的取的个数,求前缀和,显然
所以
线段树区间修改,单点查询+双指针即可
代码:
#include<cstdio>
#include<algorithm>
#define lid id<<1
#define rid id<<1|1
using namespace std;
int n,a[400005],b[400005];
struct seg_tr{
int l,r,mx,lazy;
}tr[2000005];
void build(int id,int l,int r)
{
tr[id].l=l,tr[id].r=r;
if(l==r)
{
tr[id].mx=-l;
return;
}
int mid=(l+r)>>1;
build(lid,l,mid);
build(rid,mid+1,r);
tr[id].mx=max(tr[lid].mx,tr[rid].mx);
}
void pushdown(int id)
{
if(tr[id].lazy)
{
tr[lid].lazy+=tr[id].lazy;
tr[rid].lazy+=tr[id].lazy;
tr[lid].mx+=tr[id].lazy;
tr[rid].mx+=tr[id].lazy;
tr[id].lazy=0;
}
}
void update(int id,int l,int r,int val)
{
if(tr[id].l==l&&r==tr[id].r)
{
tr[id].mx+=val;
tr[id].lazy+=val;
return;
}
pushdown(id);
int mid=(tr[id].l+tr[id].r)>>1;
if(r<=mid) update(lid,l,r,val);
else if(l>mid) update(rid,l,r,val);
else update(lid,l,mid,val),update(rid,mid+1,r,val);
tr[id].mx=max(tr[lid].mx,tr[rid].mx);
}
int main()
{
freopen("list.in","r",stdin);
freopen("list.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=1+2*n;i++)
{
scanf("%d",&a[i]);
b[a[i]]=i;
}
build(1,1,n+1);
int ans=1;
for(int i=1;i<=n*2+1;i++)
{
b[i]=min(2*n+2-b[i],b[i]);
}
for(int i=1,j=1;i<=n*2+1;i++)
{
update(1,b[i],n+1,1);
while(tr[1].mx>0)
{
update(1,b[j],n+1,-1);
j++;
}
ans=max(ans,i-j+1);
}
printf("%d",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律