NOIP2023题解

T1:词典

有一个好猜的结论:对于一个字符串,若它当中的最小字符大于等于某其他字符串中的最大字符,那么这个字符串一定不可行。

证明也很简单,若最小字符大于最大字符,显然一定不可行。若最小字符等于最大字符,由于字符串长度相同,且字符串两两不同,所以次小的一定大于另一个次大的,依然不可行,由此得证。代码及其简单,就不贴了。

T2:三值逻辑

见到这个题第一眼就可以想到并查集了。对于 true 和 false,我们可以将它们视为正负关系,这样就极大简化操作了。初始化常量,令 T = − F , U = 0 T=-F,U=0 T=F,U=0,然后我们处理完所有赋值操作后,再处理答案。

考虑一个数 x x x,在并查集中,若 x x x 祖先为 U U U,那么答案自然加 1 1 1;若它的祖先有 − x -x x,说明是非关系起冲突了,那么 x x x 只能为 U U U。由此,我们处理的重点便是如何判断 x x x 是否存在这两个祖先。

x = T / F / U x=T/F/U x=T/F/U,可以直接判断;若之前访问过 − x -x x,那么也可以判断。然后考虑 x x x 大于或小于 0 0 0 的情况,注意处理数组越界的情况,就可以了。代码不长,但细节还是比较多的。

#include<bits/stdc++.h>
using namespace std;
#define rd read()
const int N=3e5+10,T=2e5+10,F=-T,U=0;
int read(){
   
   
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){
   
   if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
	return x*f;
}
int c,t,n,m,fa[N],vis[N];
int find(int x){
   
   
	if(x==T||x==F) return x;
	if(x==U||vis[-x+n]) return U;
	if(vis[x+n]) return T;
	int res;
	if(x<0){
   
   
		if(x==-fa[-x]) return x;//为根节点
		vis[x+n]=1,res=find(-fa[-x]),vis[x+n]=0;
	}
	else{
   
   
		if(x==fa[x]) return x;
		vis[x+n]=1,res=fa[x]=find(fa[x]),vis[x+n]=0;
	}
	return res;
}
int main(){
   
   
	c=rd,t=rd;
	while(t--){
   
   
		n=rd,m=rd;memset(fa,0,sizeof(fa)),memset(vis,0,sizeof(is));
		for(int i=1;i<=n;i++) fa[i]=i;
		while(m--){
   
   
			char op;cin>>op;int x=rd,y;
			if(op=='T') fa[x]=T;
			else if(op=='F') fa[x]=F;
			else if(op=='U') fa[x]=U;
			else if(op=='+') y=rd,fa[x]=fa[y];
			else y=rd,fa[x]=-fa[y];
		}
		int ans=0;for(int i=1;i<=n;i++){
   
   
			//cout<<find(i)<<":::"<<endl;
			if(find(i)==U) ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}

T3:双序列拓展

感觉比 T4 难。

神仙思维题,依然是由特殊性质启发正解的题。

我们先看两个序列满足的条件,实际上就是对于任意位置 i i i,要么 f i > g i f_i>g_i fi>gi,要么 f i < g i f_i<g_i fi<gi,且这种大小关系只能满足一个。我们可以规定 f f f 恒小于 g g g,两种情况处理方法几乎是一样的。

先看 Subtask 1~7,可以用比较暴力的 O ( n 2 ) O(n^2) O(n2

### NOIP2024 T1 题解编程竞赛解题思路 #### 背景介绍 NOIP(全国青少年信息学奥林匹克联赛)作为国内重要的计算机科学赛事之一,旨在选拔优秀的程序设计人才。每年的比赛都会设置不同难度级别的题目来测试参赛者的算法能力和编程技巧。 #### 解析与策略制定 对于NOIP2024的第一道题目而言,通常这类题目会偏向基础概念的理解和简单应用,目的是让大部分选手能够入手并获得一定分数的同时也筛选出具备更深入思考能力的学生[^4]。 考虑到这一点,在面对T1这样的入门级挑战时,可以采取如下几种常见处理方式: - **直接求解**:如果问题本身相对直观,则可以直接通过观察数据特点找到规律进而得出结论。 - **暴力枚举**:当不确定最优解决方案时,可以通过遍历所有可能情况的方法尝试解决问题,虽然效率较低但对于小规模的数据集仍然适用。 - **模拟过程**:针对一些涉及具体操作流程的问题,按照给定条件逐步模仿实际执行步骤直至达到目标状态。 假设本年度的首题围绕着珠心算测验展开讨论,那么基于以往的经验来看,该类试题往往适合采用枚举的方式进行解答[^2]。下面给出一种具体的实现方案: ```cpp #include <iostream> using namespace std; int main() { int n; cin >> n; // 输入人数n bool flag[n+1]; memset(flag, false, sizeof(flag)); int a[n]; for(int i=1;i<=n;++i){ cin>>a[i]; for(int j=1;j<i;++j) for(int k=j+1;k<i;++k) if(a[j]+a[k]==a[i]) {flag[i]=true;break;} } int cnt=0; for(int i=1;i<=n;++i)if(!flag[i]) ++cnt; cout<<cnt<<"\n"; } ``` 上述代码实现了对每个数是否能由其他两个不同的数组合而成这一性质进行了判断,并统计满足特定条件的数量。这种方法不仅易于理解而且便于编码实现,非常适合初学者练习使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值