首页 > 其他分享 >[57] (多校联训) A层冲刺NOIP2024模拟赛15

[57] (多校联训) A层冲刺NOIP2024模拟赛15

时间:2024-10-29 19:21:41浏览次数:7  
标签:200001 15 int 57 deep 联训 ans return now

A.追逐游戏

一个非常暴力的想法是直接求出最短路径 \(S\),然后对 \(S\) 上的点,比较 \(dis_{s,S_i}\) 和 \(dis_{s',S_i}\) 的大小,如果抓捕的人先到就符合条件

实际上,这个符合条件的路径是单调的,即在最短路径上存在一个断点,断点靠近起点的一侧总不可达,靠近终点的一侧总是可达的

证明:如果 \(p\) 可达,考虑由 \(p\) 在最短路径上走一步,被追捕者也走一步,因此仍然是可达的

所以可以对内层二分答案,复杂度单次询问是二分套 LCA 的,总复杂度为 \(q\log^2 n\)

比较好的一个 trick 是用树剖求树上路径上的第 \(k\) 个点(特定点的第 \(k\) 级祖先),比较目标点是否在当前链上即可,知道这个就能快速求最短路径上的特定点了,因为这个最短路径本质是 \(x,lca,y\) 的树上简单路径,只需要维护一下深度差然后做分讨就行了

还有一个比较好的 trick

int dis(int x,int y){
	int p=lca(x,y);
	return deep[x]+deep[y]-2*deep[p];
} 

此外这个题可以通过分讨砍掉二分

如果追捕者更晚到达目标,那么答案一定是终态

否则,直接考虑两人路径的重合点,抓捕者直接在此段开始时选择向着被抓捕者走,需要的时间除二,在中点处相遇,需要处理一些特殊情况

#include<bits/stdc++.h>
using namespace std;
vector<int>e[200001];
int dfn[200001];
int size[200001],deep[200001],top[200001],fa[200001],maxson[200001];
int dfsorder[200001];
int cnt;
int n,q;
void dfs1(int now,int last){
	size[now]=1;
	deep[now]=deep[last]+1;
	fa[now]=last;
	for(auto i:e[now]){
		if(i!=last){
			dfs1(i,now);
			size[now]+=size[i];
			if(size[i]>size[maxson[now]]){
				maxson[now]=i;
			}
		}
	}
}
void dfs2(int now,int nowtop){
	dfn[now]=++cnt;
	dfsorder[cnt]=now;
	top[now]=nowtop;
	if(maxson[now]){
		dfs2(maxson[now],nowtop);
	}
	for(auto i:e[now]){
		if(i!=fa[now] and i!=maxson[now]){
			dfs2(i,i);
		}
	}
}
int lca(int a,int b){
	while(top[a]!=top[b]){
		if(deep[top[a]]<deep[top[b]]) swap(a,b);
		a=fa[top[a]];
	}
	if(deep[a]<deep[b]) swap(a,b);
	return b;
}
int lca(int a,int b,int c){
	int x1=lca(a,b),x2=lca(a,c),x3=lca(b,c);
	if(deep[x1]<deep[x2]) swap(x1,x2);
	if(deep[x1]<deep[x3]) swap(x1,x3);
	return x1;
}
int dis(int x,int y){
	int p=lca(x,y);
	return deep[x]+deep[y]-2*deep[p];
} 
int getfa(int u,int k){
	int D=deep[u]-k;
	while(deep[fa[top[u]]]>=D) u=fa[top[u]];
	return dfsorder[dfn[u]-(deep[u]-D)];
}
int getfa(int a,int b,int k){
	int p=lca(a,b);
	int d1=deep[a]-deep[p],d2=deep[b]-deep[p];
	if(d1>=k) return getfa(a,k);
	return getfa(b,d1+d2-k);
}
signed main(){
	freopen("chase.in","r",stdin);
	freopen("chase.out","w",stdout);
	cin>>n>>q;
	for(int i=1;i<=n-1;i++){
		int a,b;cin>>a>>b;
		e[a].push_back(b);
		e[b].push_back(a);
	}
	dfs1(1,0);dfs2(1,1);
	while(q--){
		int u,v,x;
		cin>>u>>v>>x;
		int p=lca(u,v,x);
		int d1=dis(x,p),d2=dis(u,p),d3=dis(p,v);
		if(d2<d1){
			cout<<d1+d3<<" "<<v<<"\n"; 
		}
		else{
			cout<<(d1+d2+1)/2<<" "<<getfa(u,x,(d1+d2+1)/2)<<"\n";
		}
	}
}

C.软件工程

发动了从暑假传到现在的传统艺能,打一堆假做法然后取 \(\max\)

赛后发现自己打的并不是假做法,而是分讨中的其中一种情况

首先有一种非常好想的,就是你对区间长度排序,然后考虑到对每个线段放一个集合里非常省事,这样它的贡献就是它自己,因此挑出最长的 \(k-1\) 个区间,每个分配一个集合,然后剩下的全丢到最后一个集合里

这个做法适用的情况是存在完全没有交集的线段时,此时假设线段 \(a,b,c\) 互相无交集,那么把它们都堆到一起是最优情况,否则总是可能会占用更多的集合导致答案变小

另一种

首先发现题目里的不超过 \(k\) 完全没有用,因为当你从划分 \(k-1\) 段改到划分 \(k\) 段的时候,要么把两个有交的线段拆开了,要么无变化,总之贡献一定是单调不减的,所以你只需要考虑划分 \(k\) 段时候的答案就行了

一种比较正常的转移一定是形如 \(f_i=\max_j (f_j+cost)\) 的,因此你直接去维护这个 \(f\)

换一种思路,设 \(f_{i,k}\) 是枚举前 \(i\) 位,第 \(i\) 位放 \(k\) 集合时 \(k\) 这单个集合的的贡献,按题意枚举最值暴力转移,复杂度 \(nk\),同时第一维可以压掉

说一下这个转移,我定义 \(cost\) 是加入这个线段对区间长度的贡献,比如加入 \([1,3]\) 到空集贡献为 \(2\),\([1,2]\) 加入 \([1,3]\) 贡献为 \(-1\),通过这个来进行转移,写起来挺像贪心的

不知道能不能再优化,我赛后就没试了

封了个类用来转移集合,应该挺好懂的

#include<bits/stdc++.h>
using namespace std;
#define int long long
template<typename T>void ignored(T x){}
struct line{
    int l,r;
    inline bool operator >(const line&A)const{
        return r-l>A.r-A.l;
    }
};
struct area{
    int l,r;
    area(){
        l=-1,r=-1;
    }
    inline int len()const{
        return l==-1ll?0ll:max(0ll,r-l);
    }
    inline area operator+(line a){
        area ans;
        if(l==-1){
            ans.l=a.l;
            ans.r=a.r;
        }
        else{
            ans.l=max(l,a.l);
            ans.r=min(r,a.r);
        }
        return ans;
    }
};
int n,m;
line a[5001];
area p[5001];
area np[5001];
signed main(){
    ignored(freopen("se.in","r",stdin));
    ignored(freopen("se.out","w",stdout));
    ignored(scanf("%lld %lld",&n,&m));
    for(int i=1;i<=n;++i){
        ignored(scanf("%lld %lld",&a[i].l,&a[i].r));
    }
    sort(a+1,a+n+1,greater<line>());
    int ans2=0;
    for(int i=1;i<=m;++i){  //策略1
        np[i]=np[i]+a[i];
    }
    for(int i=m+1;i<=n;++i){
        np[m]=np[m]+a[i];
    }
    for(int i=1;i<=m;++i){
        ans2+=np[i].len();
    }
    for(int i=1;i<=n;++i){   //策略2
        int mindx=0x3f3f3f3f,mindxid=1;
        for(int j=1;j<=m;++j){
            int tmp=p[j].len()-(p[j]+a[i]).len();//这里找的是对贡献减小量最少的
            if(tmp<mindx){
                mindx=tmp;
                mindxid=j;
            }
            else if(tmp==mindx){
                if(p[mindxid].len()>p[j].len()){
                    mindxid=j;
                }
            }//寻找最值
        }
        p[mindxid]=p[mindxid]+a[i];
    }
    int ans=0;
    for(int i=1;i<=m;++i){
        ans+=p[i].len();
    }
    cout<<max(ans,ans2);
}

标签:200001,15,int,57,deep,联训,ans,return,now
From: https://www.cnblogs.com/HaneDaCafe/p/18514169

相关文章

  • LeetCode15:三数之和
    原题地址:.-力扣(LeetCode)题目描述给你一个整数数组 nums ,判断是否存在三元组 [nums[i],nums[j],nums[k]] 满足 i!=j、i!=k 且 j!=k ,同时还满足 nums[i]+nums[j]+nums[k]==0 。请你返回所有和为 0 且不重复的三元组。注意:答案中不可以包含重复......
  • macOS Sequoia 15.1 (24B83) 正式版 ISO、IPSW、PKG 下载
    macOSSequoia15.1(24B83)正式版ISO、IPSW、PKG下载iPhone镜像、Safari浏览器重大更新和AppleIntelligence等众多全新功能令Mac使用体验再升级请访问原文链接:macOSSequoia15.1(24B83)正式版ISO、IPSW、PKG下载查看最新版。原创作品,转载请保留出处。作者主页......
  • macOS Sequoia 15.1 (24B83) Boot ISO 原版可引导镜像下载
    macOSSequoia15.1(24B83)BootISO原版可引导镜像下载iPhone镜像、Safari浏览器重大更新和AppleIntelligence等众多全新功能令Mac使用体验再升级请访问原文链接:macOSSequoia15.1(24B83)BootISO原版可引导镜像下载查看最新版。原创作品,转载请保留出处。作者主......
  • Springboot特困生在线申报和信息服务系统57is6(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表教师,贫困生,助学金申请,扶贫项目,扶贫项目申请,助学贷款,贷款申请,助学金开题报告内容一、研究背景及意义随着社会的发展和教育的普及,特困生群体在我国逐渐增......
  • 【SSM详细教程】-15-Spring Restful风格【无敌详细】
    精品专题:01.《C语言从不挂科到高绩点》课程详细笔记https://blog.csdn.net/yueyehuguang/category_12753294.html?spm=1001.2014.3001.548202.《SpringBoot详细教程》课程详细笔记https://blog.csdn.net/yueyehuguang/category_12789841.html?spm=1001.2014.3001.548203.......
  • DC/DC直流电源升压可调电压控制输出模块12v24v供电0-5v/0-10v转0-50v/80v/100v/110v/1
    特点效率高达75%以上1*2英寸标准封装单电压输出可直接焊在PCB上工作温度:-40℃~+75℃阻燃封装,满足UL94-V0要求温度特性好电压控制输出,输出电压随控制电压线性变化应用GRB系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为:4.5~9V、9~18V、18~36V及36~7......
  • ctfshow(151->154)--文件上传漏洞--.user.ini
    Web151进入界面:审计:提示是前台校验。存在图片上传。思路:先编写一个一句话木马文件://shell.php<?php@eval($_POST[1]);?>既然是前端校验,我们查看页面源代码找到相关的校验内容:说明只允许上传.png后缀的文件。我们修改代码为允许上传.php文件:然后上传一句话......
  • //找出0-1000之内符合要求的数字,要求:每一位的数字之和等于15
    //找出0-1000之内符合要求的数字,//要求:每一位的数字之和等于15//把每位数字单独提出来,相加//第一步:外循环,获取范围中的每一个数字0-1000//第二步:内循环,处理这个数字的每一位数字之和#include<stdio.h>intmain(){   intnumber1,number2,i;   for(number1......
  • 15、三数之和-cangjie
    题目15、三数之和思路1、先进行sort,将数组按序排列2、遍历三个数中的mid3、判断sum,根据sum和0的差值调整left和right4、回归了TwoSum5、需要去重,去重的时候记得倒序遍历,不然迭代器溢出代码importstd.sort.SortByExtensionimportstd.collection.*classSoluti......
  • LVGL UI设计神器助你高效开发嵌入式UI应用——v0.15.0发布(中)
    文章目录前言一、Anyui是什么?二、v0.15.0版本的特性新版本检查总结前言随着物联网的到来,凯文・凯利所预言的“屏读”时代也已来临。除了手机、平板电脑这类类似个人电脑的设备之外,越来越多的嵌入式设备也将配备触控显示屏。在资源有限的嵌入式设备上构建一个出......