PTA L2难度

L2-004 这是二叉搜索树吗?

code:

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const int maxn = 1e3 + 9;
int n;
int a[maxn], cnt;
struct tree
{
	int val, ls, rs;
}tr[maxn << 2];
int path[maxn];
inline void add(int x, int rt)
{
	if(tr[x].val < tr[rt].val)
	{
		if(tr[rt].ls) add(x, tr[rt].ls);
		else tr[rt].ls = x;
	}
	else
	{
		if(tr[rt].rs) add(x, tr[rt].rs);
		else tr[rt].rs = x;
	}
}
void dfs1(int rt)// 前序 
{
	path[++cnt] = tr[rt].val;
	if(tr[rt].ls) dfs1(tr[rt].ls);
	if(tr[rt].rs) dfs1(tr[rt].rs);
}
void dfs2(int rt)// 后续 
{
	if(tr[rt].ls) dfs2(tr[rt].ls);
	if(tr[rt].rs) dfs2(tr[rt].rs);
	path[++cnt] = tr[rt].val;
}
void dfs3(int rt)// 镜像前序 
{
	path[++cnt] = tr[rt].val;
	if(tr[rt].rs) dfs3(tr[rt].rs);
	if(tr[rt].ls) dfs3(tr[rt].ls);
}
void dfs4(int rt)// 镜像后序 
{
	if(tr[rt].rs) dfs4(tr[rt].rs);
	if(tr[rt].ls) dfs4(tr[rt].ls);
	path[++cnt] = tr[rt].val;
}
void work()
{
	cin >> n;
	for(int i = 1; i <= n; ++i) cin >> tr[i].val;
	for(int i = 2; i <= n; ++i) add(i, 1);
	bool f = 1;
	dfs1(1);
	for(int i = 1; i <= cnt; ++i) if(path[i] != tr[i].val)
	{
		f = 0; break;
	}
	if(f)
	{
		cnt = 0;
		dfs2(1);
		cout << "YES\n";
		for(int i = 1; i <= n; ++i)
			cout << path[i] << " \n"[i==n];
		return;
	}
	cnt = 0;f = 1;
	dfs3(1);
	for(int i = 1; i <= n; ++i) if(path[i] != tr[i].val)
	{
		f = 0; break;
	}
	if(f)
	{
		cnt = 0;
		dfs4(1);
		cout << "YES\n";
		for(int i = 1; i <= n; ++i)
			cout << path[i] << " \n"[i==n];
		return;
	}
	cout << "NO" << endl;
}

int main()
{
	ios::sync_with_stdio(0);
	work();
	return 0;
}

L2-006 树的遍历 (25 分)
根据后序遍历与中序遍历建二叉树
可以学一下手动还原
代码就是模拟的这种还原方式
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ls (p << 1)
#define rs (p << 1 | 1)
using namespace std;
const int maxn = 1e5 + 9;
const int mod = 1e9 + 7;
ll n, m;
int last[maxn], mid[maxn], ans[maxn];

void build(int l, int r, int rt, int p)
{
	if(l > r) return;
	int pos = l;
	while(pos <= r && mid[pos] != last[rt]) ++pos;
	ans[p] = last[rt];
	build(l, pos - 1, rt - 1 - (r - pos), ls);
	build(pos + 1, r, rt - 1, rs);
}

void work()
{
	memset(ans, -1, sizeof(ans));
	cin >> n;
	for(int i = 1; i <= n; ++i) cin >> last[i];
	for(int i = 1; i <= n; ++i) cin >> mid[i];
	build(1, n, n, 1);
	vector <int> v;
	for(int i = 1; i < maxn; ++i) if(ans[i] != -1)
		v.push_back(ans[i]);
	for(int i = 0; i < (int)v.size() - 1; ++i) cout << v[i] << " ";
	cout << v.back() << endl;
}

int main()
{
	ios::sync_with_stdio(0);
	//int TT;cin>>TT;while(TT--)
	work();
	return 0;
}


L2-014 列车调度 (25 分)
裸的最长上升子序列(如果你知道Dilworth定理

code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define eps 1e-3
using namespace std;
const int maxn = 1e5 + 9;
const int mod = 1e9 + 7;
ll n, m;
void work()
{
	int n;
	cin >> n;
	set <int> se;
	for(int i = 1; i <= n; ++i)
	{
		int x;cin >> x;
		auto it = se.lower_bound(x);
		if(it != se.end())
		{
			se.erase(*it);
			se.insert(x);
		}
		else se.insert(x);
	}
	cout << se.size();
}

int main()
{
	ios::sync_with_stdio(0);
	//int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

L2-013 红色警报 (25 分)
这个题和这个第四题差不多
离线查询,倒着遍历查询
并查集维护连通块
如果加入一个点,这个点连接了至少两个连通块,那么就是发出红色警报的
我们用 s e t set set 维护一下这个点连接的所有可连接点的 f a t h e r father father 即可判断连通块个数
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
const int maxn = 1e3 + 9;
const int mod = 1e9 + 7;
int n, m;
int f[maxn];
int pos[maxn];
vector <int> e[maxn];
int Find(int x)
{
	return x == f[x] ? x : f[x] = Find(f[x]);
}
void work()
{
	cin >> n >> m;
	for(int i = 0; i < n; ++i) f[i] = i;
	for(int i = 1; i <= m; ++i)
	{
		int x, y;cin >> x >> y;
		e[x].push_back(y);e[y].push_back(x);
	}
	int k;cin >> k;
	vector <int> q;
	for(int i = 1; i <= k; ++i)
	{
		int x;cin >> x;
		q.push_back(x);
		pos[x] = 1;
	}
	for(int i = 0; i < n; ++i) if(!pos[i])
	{
		for(int j = 0; j < e[i].size(); ++j) if(!pos[e[i][j]])
		{
			int x = Find(i), y = Find(e[i][j]);
			if(x != y) f[x] = y;
		}
	}
	stack <string> s;
	for(int i = k - 1; i >= 0; --i)// 先把没有被占领的节点连接处理一下
	{
		pos[q[i]] = 0;
		set<int> se;
		for(int j = 0; j < e[q[i]].size(); ++j) if(!pos[e[q[i]][j]])
		{
			int x = Find(q[i]), y = Find(e[q[i]][j]);
			if(x != y){
				f[y] = x;
				se.insert(y);
			}
		}
		if(se.size() > 1) {
			string s1 = "Red Alert: City ";
			string s2 = " is lost!";
			string s3 = to_string(q[i]);
			s.push(s1 + s3 + s2);
		}
		else {
			string s1 = "City ";
			string s2 = " is lost.";
			string s3 = to_string(q[i]);
			s.push(s1 + s3 + s2);
		}
	}
	while(!s.empty())
	{
		cout << s.top();
		s.pop();
		if(s.size() || k == n) cout << endl;
	}
	if(k == n) cout << "Game Over.";
}	

int main()
{
	ios::sync_with_stdio(0);
	//int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

L2-023 图着色问题 (25 分)
坑点是这 K 个颜色必须全部用上,否则不算一个解
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define eps 1e-3
using namespace std;
const int maxn = 1e6 + 9;
const int mod = 1e9 + 7;
ll n, m;
int V, E, K;
struct Edge
{
	int to, next;
}e[maxn];
int head[maxn], cnt, vis[maxn], color[maxn];

inline void add(int x, int y)
{
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}
bool check()
{
	for(int i = 1; i <= V; ++i)
	{
		for(int j = head[i]; j; j = e[j].next)
		{
			int to = e[j].to;
		//cout << i << " " << color[i] << " " << to << " " << color[to] << endl;
			if(color[i] == color[to]) return false;
		}
	}
	return true;
}
void work()
{
	cin >> V >> E >> K;
	for(int i = 1; i <= E; ++i)
	{
		int x, y;cin >> x >> y;
		add(x, y);add(y, x);	
	}
	int k;cin >> k;
	for(int i = 1; i <= k; ++i)
	{
		set<int> se;
		for(int j = 1; j <= V; ++j)
			cin >> color[j], se.insert(color[j]);
		if(se.size() == K && check()) cout << "Yes\n";
		else cout << "No\n";
	}
}

int main()
{
	ios::sync_with_stdio(0);
	//int TT;cin>>TT;while(TT--)
	//while(cin >> n)
	work();
	return 0;
}

L2-001 紧急救援 (25 分)
和里面的英文版 Emergency 几乎一样
用个 pre 记录下路径就完事了
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
const int maxn = 1e6 + 9;
const int mod = 1000000009;
const int inf = 0x3f3f3f3f;

int n, m;
struct node
{
	int to, next, w;
}e[maxn * 2];
int head[maxn], cnt;
int pre[maxn];
inline void add(int x, int y, int z)
{
	e[++cnt].to = y;
	e[cnt].next = head[x];
	e[cnt].w = z;
	head[x] = cnt;
}
int dis[maxn], ans[maxn], W[maxn], res[maxn];
bool vis[maxn];
priority_queue <pair<int,int>, vector<pair<int,int> >, greater<pair<int,int> > > q;
void work()
{
	int c1, c2;
	cin >> n >> m >> c1 >> c2;
	int u, v, w;
	for(int i = 0; i < n; ++i) cin >> W[i];
	for(int i = 1; i <= m; ++i)
	{
		cin >> u >> v >> w;add(u, v, w);add(v, u, w);
	}
	for(int i = 0; i < n; ++i)
		dis[i] = 1e9, vis[i] = 0;
	dis[c1] = 0, ans[c1] = 1;
	q.push({0, c1});
	res[c1] = W[c1];// 初始化起点价值
	while(!q.empty())
	{
		int now = q.top().second;q.pop();
		if(vis[now]) continue;
		vis[now] = 1;
		for(int i = head[now]; i; i = e[i].next)
		{
			int tmp = e[i].to;
			if(dis[tmp] > dis[now] + e[i].w)
			{
				dis[tmp] = dis[now] + e[i].w;
				ans[tmp] = ans[now];
				res[tmp] = res[now] + W[tmp];
				pre[tmp] = now;
				q.push({dis[tmp], tmp});
			}
			else if(dis[tmp] == dis[now] + e[i].w)
			{
				ans[tmp] += ans[now];
				if(res[tmp] < res[now] + W[tmp]) pre[tmp] = now;
				res[tmp] = max(res[tmp], res[now] + W[tmp]);
			}
		}
	}
	cout << ans[c2] << " " << res[c2] << endl;
	stack <int> st;
	int j = c2;
	while(j != c1)
	{
		st.push(j);
		j = pre[j];
	}
	st.push(c1);
	while(!st.empty())
	{
		cout << st.top();
		st.pop();
		if(st.size()) cout << " ";
		else cout << endl;
	}
} 

int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	//int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

1010 Radix (25 分)
题意:
给定两个不超过 9 9 9 为的数,一个 t a g tag tag 表示 后边的进制 b a s e base base 是第一个数还是第二个数,对于不知道进制的数,找到一个合理的进制,使得两个数相等
思路:
这个题保证了给进制的数转化成 10 10 10 进制不会爆 l l ll ll(虽然它没说
二分答案,当前进制为 m i d mid mid,转成 10 10 10 进制如果爆 l l ll ll 或者 大于 n u m num num_ a a a,则说明 m i d mid mid 偏大
ps:感觉这个题好难写

code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
const int maxn = 1e5 + 9;
const int mod = 1e9 + 7;
unordered_map<char, int> ma;
ll n, m;
ll to_num(string s, ll base)
{
	ll ans = 0;
	for(int i = 0; i < s.size(); ++i)
		ans = ans * base + ma[s[i]];
	return ans;
}
void work()
{
	for(int i = 0; i < 36; ++i)
	{
		char tmp = i < 10 ? i + '0' : i - 10 + 'a';
		ma[tmp] = i;
	}
	string a, b;
	ll k, num;
	cin >> a >> b >> k >> num;
	if(k == 2) swap(a, b);

	ll num_a = to_num(a, num);
	ll l = -1,  r = num_a;
	
	for(auto x : b) l = max(l, 1ll * (ma[x] + 1));
	while(l < r)
	{
		ll mid = (l + r) >> 1;
		ll t = to_num(b, mid);
		if(t < 0 || t >= num_a) r = mid;
		else l = mid + 1;
	}
	if(to_num(b, l) != num_a) l = -1;
	if(l == -1) cout << "Impossible\n";
	else cout << l << endl;
}

int main()
{
	ios::sync_with_stdio(0);
	//int TT;cin>>TT;while(TT--)
	work();
	return 0;
}
### PTA L2-042 老板的作息表 解题思路 此问题的核心在于处理时间段之间的关系,找出未被覆盖的时间区间。可以通过以下方法解决: #### 数据结构设计 为了高效地解决问题,可以采用如下数据结构: 1. 将每个时间转换为自午夜以来经过的总秒数,便于比较和计算。 2. 使用列表存储所有已知的时间段。 #### 主要逻辑流程 1. **输入解析**:读取并解析输入中的每段时间,将其转化为起始时间和终止时间对应的秒数[^2]。 2. **排序操作**:将所有时间段按照起始时间升序排列,如果起始时间相同,则按终止时间降序排列。 3. **合并重叠区间**:遍历排序后的区间列表,合并可能存在的相邻或重叠区间。 4. **查找空闲区间**:通过对比当前区间的终点与下一个区间的起点,找到两者之间不存在的时间段,并记录下来。 5. **结果输出**:将得到的空闲时间段重新格式化为 `hh:mm:ss - hh:mm:ss` 的形式输出。 以下是基于上述分析的具体 Python 实现代码: ```python def time_to_seconds(time_str): """将时间字符串 'hh:mm:ss' 转换为从零点开始的秒数""" h, m, s = map(int, time_str.split(':')) return h * 3600 + m * 60 + s def seconds_to_time(seconds): """将秒数转换回时间字符串 'hh:mm:ss'""" h = seconds // 3600 m = (seconds % 3600) // 60 s = seconds % 60 return f"{h:02}:{m:02}:{s:02}" n = int(input()) intervals = [] for _ in range(n): start, _, end = input().split() intervals.append((time_to_seconds(start), time_to_seconds(end))) # 对区间按起始时间排序 intervals.sort() merged_intervals = [] prev_start, prev_end = None, None # 合并重叠区间 for current_start, current_end in intervals: if prev_start is None: prev_start, prev_end = current_start, current_end elif current_start <= prev_end: prev_end = max(prev_end, current_end) else: merged_intervals.append((prev_start, prev_end)) prev_start, prev_end = current_start, current_end merged_intervals.append((prev_start, prev_end)) free_slots = [] if merged_intervals[0][0] != 0: free_slots.append(f"00:00:00 - {seconds_to_time(merged_intervals[0][0])}") for i in range(len(merged_intervals) - 1): gap_start = merged_intervals[i][1] gap_end = merged_intervals[i + 1][0] if gap_start < gap_end: free_slots.append(f"{seconds_to_time(gap_start)} - {seconds_to_time(gap_end)}") if merged_intervals[-1][1] != 86399: free_slots.append(f"{seconds_to_time(merged_intervals[-1][1])} - 23:59:59") print("\n".join(free_slots)) ``` 以上代码实现了完整的解法,涵盖了从输入到最终输出的所有步骤。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值