ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[整理]qbxt周末刷题班 Day2总结

2020-11-03 21:03:05  阅读:222  来源: 互联网

标签:nxt le ok int Day2 qbxt rg now 刷题


跑路

Description:有一棵无根树,给定一个温泉,问至少再添加多少温泉,使得所有叶节点(度为1)到温泉的距离不超过\(k\)。
Solution:我们考虑贪心地放温泉。一个简单的思路是对于一个节点\(x\),总是放到它的祖先处。但是这样做有一个问题:如果一个兄弟子树中的节点\(y\)原本被\(t\)覆盖,但是挪到\(LCA(x,t)\)之后覆盖不到了怎么办?其实解决办法很简单,我们按照深度从大到小排即可。
Implementation:有了贪心策略的证明后实现就很简单了:每次放到\(k\)级祖先,然后标记能覆盖到的点。
Code:

#define N 1010
int T,n,s,k;
int fa[N],ind[N],cov[N];
vector<int>p[N];//p[dep][i]:person at level dep
struct Edge {
	int to,nxt;
}e[N<<1];
int head[N],cnt;
inline void ade(int u,int v){
	e[++cnt].to=v,e[cnt].nxt=head[u],head[u]=cnt,ind[v]++;
}
void DFS(int now,int ff,int dep){
	fa[now]=ff;
	if(ind[now]==1&&dep>k)p[dep].pub(now);
	for(rg int i=head[now];i;i=e[i].nxt){
		int v=e[i].to;
		if(v!=ff)DFS(v,now,dep+1);
	}
}
void Cover(int now,int ff,int step){
	cov[now]=1;
	if(step==k)return;
	for(rg int i=head[now];i;i=e[i].nxt){
		int v=e[i].to;
		if(v!=ff){
			Cover(v,now,step+1);
		}
	}
}
int main(){
	Read(T);
	while(T--){
		memset(fa,0,sizeof(fa)),memset(ind,0,sizeof(ind));
		memset(head,0,sizeof(head)),cnt=0;
		memset(cov,0,sizeof(cov));
		for(rg int i=0;i<N;i++)p[i].clear();
		Read(n),Read(s),Read(k);
		for(rg int i=1;i<n;i++){
			int u,v;Read(u),Read(v);
			ade(u,v),ade(v,u);
		}
		DFS(s,-1,0);
		int ans=0;
		for(rg int i=n-1;i>k;i--){
			for(rg int j=0;j<p[i].size();j++){
				int v=p[i][j];
				if(!cov[v]){
					int ff=v,kk=k;
					while(kk--)ff=fa[ff];
					Cover(ff,-1,0);ans++;
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

卡牌

Description:有\(n\)个元素,每个元素有三个属性\(A,B,C\),规定偏序关系\(p_i<p_j\)当且仅当\(A_i<=A_j\& B_i<=B_j\& C_i<=C_j\),请你挑出一些元素,使得它们排序后能单调上升,求最多挑出多少个。
两部分数据:Part 1满足\(n,B,C\le 10^6\& C=0\),Part 2满足\(n\le 10^3\& A,B,C\le10^6\)。
Solution:对于\(C=0\)的情况,可以套用二位偏序的做法,此处不再赘述。对于\(C\ne0\)的情况,我们把两个元素之间的偏序关系连成有向边,然后在这个图里求最长路即可。
Code:

#define N 1010
#define Nmax 1000010
int n;
struct Card {
	int a,b,c;
	Card(int _a=0,int _b=0,int _c=0){
		a=_a,b=_b,c=_c;
	}
}cd[Nmax];
bool operator < (Card x,Card y){
	return (x.a<=y.a)&&(x.b<=y.b)&&(x.c<=y.c);
}
namespace Case2 {
	int ind[N],dis[N],ans=0;
	struct Edge {
		int to,nxt;
	}e[N*N];
	int head[N],cnt;
	inline void ade(int u,int v){
		e[++cnt].to=v,e[cnt].nxt=head[u];
		head[u]=cnt,ind[v]++;
	}
	void Topo(){
		queue<int>q;
		for(rg int i=1;i<=n;i++){
			if(!ind[i]){
				q.push(i),dis[i]=1;
			}
		}
		while(!q.empty()){
			int u=q.front();q.pop();
			for(rg int i=head[u];i;i=e[i].nxt){
				int v=e[i].to;
				dis[v]=dis[u]+1;
				ans=max(ans,dis[v]);
				if(!--ind[v]){
					q.push(v);
				}
			}
		}
	}
	void main(){
		for(rg int i=1;i<=n;i++){
			for(rg int j=1;j<=n;j++){
				if(i!=j&&cd[i]<cd[j]){
					ade(i,j);
				}
			}
		}
		Topo();
		cout<<ans<<endl;
	}
}
namespace Case3 {
	inline bool cmp(Card x,Card y){
		return (x.a==y.a)?(x.b<y.b):(x.a<y.a);
	}
	int c[Nmax];
	inline int lowbit(int x){
		return x&(-x);
	}
	inline void Modify(int pos,int num){
		while(pos<Nmax){
			c[pos]=max(c[pos],num);
			pos+=lowbit(pos);
		}
	}
	inline int Query(int pos){
		int res=0;
		while(pos){
			res=max(res,c[pos]);
			pos-=lowbit(pos);
		}
		return res;
	}
	void main(){
		int ans=0;
		sort(cd+1,cd+1+n,cmp);
		for(rg int i=1;i<=n;i++){
			int tmp=Query(cd[i].b)+1;
			ans=max(ans,tmp);
			Modify(cd[i].b,tmp);
		}
		cout<<ans<<endl;
	}
} 
int main(){
	Read(n);
	for(rg int i=1;i<=n;i++)Read(cd[i].a),Read(cd[i].b),Read(cd[i].c);
	if(n<=1000)Case2::main();
	else Case3::main();
	return 0;
}

数列

Description:有一个数列\(\{a_i\}\)满足:

\[a_i=\begin{cases}i,(i\le 2)\\2a_{i-1},(i>2,2\nmid i)\\a_{i-1}+b{i-1},(i>2,2|i)\end{cases} \]

其中\(b_k=mex\{|a_i-a_j|\}(1\le i,j\le k)\)。
Solution:我们算出这个奇怪的数列的前几项会发现一个规律:它增长得非常快而且对于前\(k\)项来说,它与之后的项无法贡献有用的差值,而能影响答案的差值只能是\(+b_{i-1}\)时贡献的。
根据\(mex\)的定义,我们可以形象地认为,每贡献一个新的差值,就是在填补之前的缺口。那么假设我们询问的是\(x\),前\(k\)项里出现的所有差值为\(S\),那么新的\(mex\)就要先填补\(S\)中那些不到\(x\)的差值(设为\(d\)个),而\(mex\)隔项出现,最终答案即为\(k+2d+1\)和\(k+2d+2\)。
Code:代码又咕咕了

火锅

Description:有\(n\)盘肉,每盘肉有两个参数\(a_i,b_i\)分别代表了出锅时间和食用时间。对于每个\(k\le n\),求出在挑\(k\)盘肉自定顺序吃掉时的最短时间。
Solution:本题重点是按照\(a_i\)排序的贪心,有了这个贪心后就可以使用各种奇奇怪怪的方法A掉本题。
Implementation:使用小根堆维护\(b_i\),然后根据需要更新下一盘吃的肉。
Code:

#define N 300010
int n;
struct Meat {
	int ok,eat;
}m[N];
bool operator < (Meat a,Meat b){
	return a.ok<b.ok;
}
signed main(){
	Read(n);
	for(rg int i=1;i<=n;i++)Read(m[i].ok),Read(m[i].eat);
	sort(m+1,m+1+n);
	priority_queue<int,vector<int>,greater<int> >q;
	int now=0,nxt=1,tim=0;
	q.push(INF),m[n+1].ok=INF;
	while(now<n){
		if(tim>=m[nxt].ok){
			q.push(m[nxt++].eat);
		}
		int u=q.top();q.pop();
		if(m[nxt].ok-tim>=u){
			now++,tim+=u;
			cout<<tim<<" ";
		}else {
			u-=(m[nxt].ok-tim);
			tim=m[nxt].ok;
			q.push(u);
		}
	}
	return 0;
}

完结撒花

标签:nxt,le,ok,int,Day2,qbxt,rg,now,刷题
来源: https://www.cnblogs.com/juruoajh/p/13922506.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有