USACO 2024 Open Bronze铜组题解

迟到了一个月的题解......

Logical Moos:

啊这题放在铜组T1雀食有点BT......

首先,我们关注l前第一和r最后那两组。如果这俩有一个是true,那答案肯定也是true。

否则,在l和r外边的都是false。那我们就只用仔细看l和r中间的玩意儿。对于l和r中间的每一组,只要第一组和最后一组都是false,那结果肯定也是false。

所以:如果换掉的对最后结果木有影响,那就不管;如果有,就换。

对于true的查询,我们必须再次检查该段是否包含l这组的第一个false,以及r这组的最后一个false。如果不是,那么即使我们将其余部分替换为true,结果也将还是false。

对于false的查询,如果输入是false,结果将为false。

我们每次只需记录每组中最左的false和最右的false,复杂度\Theta (N+Q)

#include <bits/stdc++.h>
using namespace std;
string expr[maxn];
int group[maxn];
int main(){
	int N,Q;
	cin>>N>>Q;
	for(int i=0;i<N;i++)
		cin>>expr[i];
	int idx=0;
	for(int i=0;i<N;i++){
		if(expr[i]=="or")
			idx++;
		else{
			if(i%2==0)
				group[i]=idx;
		}
	}
	vector<int> first_false(idx+1,INF);
	vector<int> last_false(idx+1,-1);
	for(int i=0;i<N;i+=2){
		int g=group[i];
		if(expr[i]=="false"){
			if(first_false[g]==INF)
				first_false[g]=i;
			last_false[g]=i;
		}
	}
	int first_true=INF,last_true=-1;
	for(int i=0;i<=idx;i++){
		if(first_false[i]==INF){
			if(first_true==INF)
				first_true=i;
			last_true=i;
		}
	}
	while(Q--){
		int l,r;
		cin>>l>>r;
		--l;
		--r;
		string query;
		cin>>query;
		int gl=group[l],gr=group[r];
		if(first_true<gl || last_true>gr){
			cout<<(query=="true"?'Y':'N');
			continue;
		}
		if(query=="true")
			cout<<(first_false[gl]<l || last_false[gr]>r?'N':'Y');
		else
			cout<<'Y';
	}
	return 0;
}

好长啊。。。

Walking Along a Fence:

我们用一个二维矩阵记录每个点沿栅栏的距离,我们按顺序读入栅栏,当我们这样做时,我们遍历栅栏上的每个点,在数组中标记每个点0,1,2,…;同时记录周长。由于篱笆最多访问每个点一次,时间复杂度为\Theta (L^2)

#include <bits/stdc++.h>
using namespace std;
const int MAX=200005;
struct loc{
	int x;
	int y;
}posts[MAX];
int perimeter,dist[1005][1005];
void walk(loc st,loc ed){
	diff.x=ed.x-st.x,diff.y=ed.y-st.y;
	int dis=abs(diff.x)+abs(diff.y);
	diff.x=diff.x/dis,diff.y=diff.y/dis;
	for(int i=0;i<dis;i++){
		dist[st.x][st.y]=perimeter;
		perimeter++;
		st.x=st.x+diff.x,st.y=st.y+diff.y;
	}
}
int main(){
	int N,P;
	cin>>N>>P;
	for(int i=0;i<P;i++)
		cin>>posts[i].x>>posts[i].y;
	for(int i=0;i<P;i++)
		walk(posts[i],posts[(i+1)%P]);
	for(int i=0;i<N;i++){
		int x1,y1,x2,y2;
		cin>>x1>>y1>>x2>>y2;
		int p1=dist[x1][y1];
    	int p2=dist[x2][y2];
    	int ans=abs(p1-p2);
		ans=min(ans,perimeter-ans);
		cout<<ans<<endl;
	}
	return 0;
}

Farmer John's Favorite Permutation:

Farmer Nhoj????????????????????????????????????????????????????????????

Emmmmmmmmmm,\Theta (N!)暴力的话肯定是不行的。那怎么办呢?

我们会发现,不管怎么动,1,永远不会动。所以,1,必然是那个活到最后的人。h_{N-1}=1。否则直接不可以总司令然后走人。

如果不是-1,我们就把最后一个从h里踢出去,不管它。

那p的最小字典序一定满足p_1<p_N。接下来,我们会想:只有一组这样的p吗?

我们知道,h都是不同的,看起来,如果存在一些映射到h的p,p必然是唯一的。

大家可以手推一下,把h和p都算出来,可以发现这两点:

        1. 每个h里的元素都是不同的

        2. p结尾的数正好是从h里消失的两个。

所以,只要确定了p结尾的数,就可以得出整个p。

#include <bits/stdc++.h>
using namespace std;
int main(){
	int T;
	cin>>T;
	while(T--){
		int N;
		cin>>N;
		vector<int> h(N-1);
		for(auto &x:h)
			cin>>x;
		vector<bool> has(N+1);
		for(int x:h)
			has[x]=true;
		vector<int> not_has;
		for(int i=1;i<=N;i++){
			if(!has[i])
				not_has.push_back(i);
		}
		int cnt_one=count(h.begin(),h.end(),1);
		if(not_has.size()>2 || h.back()!=1 || (not_has.size()==2 && cnt_one!=2)){
			cout<<-1<<endl;
			continue;
		}
		vector<int> p(N);
		if(not_has.size()==1){
			p[0]=1;
			p[N-1]=not_has[0];
		}
		else{
			p[0]=not_has[0];
			p[N-1]=not_has[1];
		}
		int l=0,r=N-1;
		for(int i=0;i<N-1;i++){
			if(p[l]>p[r])
				p[++l]=h[i];
			else
				p[--r]=h[i];
		}
		for(int i=0;i<N;i++)
			cout<<p[i];
		cout<<endl;
	}
	return 0; 
}

好了,以上就是本期的全部内容了。我们下期再见!\(^o^)/~

友情提示:本期的代码都有问题,请不要无脑Ctrl C+Ctrl V

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值