2025.6.22-2025.6.23做题记录

前言

中考一周年啊,能不能放我进去圆我数学和理综AK梦啊啊啊啊啊啊的`(>﹏<)′

推积木KLO

如果 \(f_{i,j}\)表示第 \(i\) 个方块,删除 \(j\) 个的最优解,感觉上没法优化(因为是个背包),所以扔了。
换一个 \(f_i\) 表示第 \(i\) 个方块必须在位置上时的最优解,那么 \(f_{a_i}=\max f_{a_j}+1\) 转移。
问题是转移的条件。
转移条件如下:\(i>j,a_i>a_j,a_i-a_j\le i-j\) 。其实是二维偏序。
移项得到 \(i-a_i\ge j-a_j\) 按照 \(i-a_i\) 升序排序,再用树状数组限制一维,同时转移。

点击查看代码
#include<bits/stdc++.h>

using namespace std;
const int N=1e5+10;
const int M=1e6+10;
int n;
struct BIT{
#define lowbit(i) i&-i
	int tr[M];
	void update(int x,int k){
		if(!x) return ;
		for(int i=x;i<=n;i+=lowbit(i)){
			tr[i]=max(k,tr[i]);
		}
	}
	int query(int x){
		int res=0;
		for(int i=x;i;i-=lowbit(i)){
			res=max(tr[i],res);
		}
		return res;
	}
}T;
struct node{
	int x,id;
}a[N];
bool cmp(node a,node b){
	return (a.id-a.x==b.id-b.x) ? a.id<b.id : a.id-a.x<b.id-b.x;
}
int res=0,ans;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].x;
		a[i].id=i;
	}
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++){
		if(a[i].id-a[i].x<0) continue;
		res=T.query(a[i].x-1)+1;
		ans=max(res,ans);
		T.update(a[i].x,res);
	}
	cout << ans;
	return 0;
}

跳跳棋

只要发现题目中的跳跃是类似一棵二叉树时,我们已经做完80%了。
树上的节点是一个三元组表示三个点的位置。
中间点向两侧跳 是儿子,两侧只有一个点能向中间跳 是父亲节点。
我们把树建出来,根节点相同就代表能跳一起,最少步数就是 LCA。

关键是有 1e9 的数据范围,所以我们需要减少建树这一步骤。
发现如果两个点来回翻滚,另一个点不动的过程是固定的,这一步我们拿除法做。

后续正常的 LCA 即可。实现类似倍增求 LCA。

点击查看代码
#include<bits/stdc++.h>

using namespace std;
int a[4],b[4];
struct node{
	int a,b,c,tot;
}A,B;
bool cmp(node a,node b){
	return a.tot<b.tot;
}
void dfs(int a,int b,int c){
	int tot=0;
	while(1){
		int d1=b-a,d2=c-b;
		if(d1==d2) break;
		if(d1<d2){
			int d3=(d2-1)/d1;
			tot+=d3;
			a+=d1*d3;
			b+=d1*d3;
		}else{
			int d3=(d1-1)/d2;
			tot+=d3;
			c-=d2*d3;
			b-=d2*d3;
		}
	}
	if(A.a||A.b) B={a,b,c,tot};
	else A={a,b,c,tot};
}
bool check(int T,int a,int b,int c,int x,int y,int z){
	int tot=T;
	while(tot){
		int d1=b-a,d2=c-b;
		if(d1==d2) break;
		if(d1<d2){
			int d3=min((d2-1)/d1,tot);
			tot-=d3;
			a+=d1*d3;
			b+=d1*d3;
		}else{
			int d3=min((d1-1)/d2,tot);
			tot-=d3;
			c-=d2*d3;
			b-=d2*d3;
		}
	}
	tot=T;
	while(tot){
		int d1=y-x,d2=z-y;
		if(d1==d2) break;
		if(d1<d2){
			int d3=min((d2-1)/d1,tot);
			tot-=d3;
			x+=d1*d3;
			y+=d1*d3;
		}else{
			int d3=min((d1-1)/d2,tot);
			tot-=d3;
			z-=d2*d3;
			y-=d2*d3;
		}
	}
	return a==x && b==y && c==z;
}
int ans1,ans2;
int main(){
	cin>>a[1]>>a[2]>>a[3]>>b[1]>>b[2]>>b[3];	
	sort(a+1,a+1+3);sort(b+1,b+1+3);
	dfs(a[1],a[2],a[3]);
	dfs(b[1],b[2],b[3]);
	if(A.a!=B.a || A.b!=B.b || A.c!=B.c){
		cout << "NO";
		return 0;
	}
	if(A.tot<B.tot){
		swap(A.a,B.a);
		swap(A.b,B.b);
		swap(A.c,B.c);
		swap(A.tot,B.tot);
		swap(a,b);
	}
	int tot=A.tot-B.tot;
	ans1=tot;
	while(tot){
		int d1=a[2]-a[1],d2=a[3]-a[2];
		if(d1==d2) break;
		if(d1<d2){
			int d3=min((d2-1)/d1,tot);
			tot-=d3;
			a[1]+=d1*d3;
			a[2]+=d1*d3;
		}else{
			int d3=min((d1-1)/d2,tot);
			tot-=d3;
			a[3]-=d2*d3;
			a[2]-=d2*d3;
		}
	}
	int l=0,r=B.tot;
	while(l<=r){
		int mid=(l+r)>>1;
		if(check(mid,a[1],a[2],a[3],b[1],b[2],b[3])){
			ans2=mid;
			r=mid-1;
		}else{
			l=mid+1;
		}
	}
	cout<<"YES\n" << ans1+ans2*2;
	return 0;
}
posted @ 2025-06-23 16:48  Tighnari  阅读(19)  评论(0)    收藏  举报