天梯赛L2刷题(也就写写水题骗骗自己了)

目录

[L2-001 紧急救援](#L2-001 紧急救援)

[L2-002 链表去重](#L2-002 链表去重)

[L2-003 月饼](#L2-003 月饼)

[L2-004 这是二叉搜索树吗?](#L2-004 这是二叉搜索树吗?)

[L2-005 集合相似度](#L2-005 集合相似度)

[L2-006 树的遍历](#L2-006 树的遍历)

[L2-007 家庭房产](#L2-007 家庭房产)

[L2-008 最长对称子串](#L2-008 最长对称子串)

[L2-009 抢红包](#L2-009 抢红包)

[L2-053 算式拆解](#L2-053 算式拆解)

[L2-054 三点共线](#L2-054 三点共线)

[L2-055 胖达的山头](#L2-055 胖达的山头)

[L2-056 被n整除的n位数](#L2-056 被n整除的n位数)


L2-001 紧急救援

Dijkstra模板(暂时不会)

L2-002 链表去重

感觉是一道大模拟

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
struct Node{
	int data;
	int next;
}node[100005];
int keep[100005];
int dele[100005];
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	unordered_map<int,int>map;
	int start,n;
	cin>>start>>n;
	for(int i=0;i<n;i++){
		int arr;cin>>arr;
		cin>>node[arr].data>>node[arr].next;
	}
	int cnt1=0;
	int cnt2=0;
	int p=start;
	while(p!=-1){
		int x=abs(node[p].data);
		if(map.count(x))dele[cnt2++]=p;
		else {
			keep[cnt1++]=p;
			map[x]++;
		}
		p=node[p].next; 
	}
	for(int i=0;i<cnt1;i++){
		printf("%05d %d ",keep[i],node[keep[i]].data);
		if(i!=cnt1-1)printf("%05d\n",keep[i+1]);
		else printf("-1\n");
	}
	for(int i=0;i<cnt2;i++){
		printf("%05d %d ",dele[i],node[dele[i]].data);
		if(i!=cnt2-1)printf("%05d\n",dele[i+1]);
		else printf("-1\n");
	}
	return 0;
}

L2-003 月饼

贪心入门题

注意double型用f输出

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;
double d;
struct Node{
	double score;//库存 
	double pay;//总价 
	double val;//单价 
};
bool com(const Node &a,const Node &b){
	return a.val>b.val;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n>>d;
	vector<Node>s(n);
	for(int i=0;i<n;i++)cin>>s[i].score;
	for(int i=0;i<n;i++)cin>>s[i].pay;
	for(int i=0;i<n;i++)s[i].val=s[i].pay/s[i].score;
	sort(s.begin(),s.end(),com);
	double ans=0;
	for(int i=0;i<n;i++){
		if(d>=s[i].score){
			d-=s[i].score;
			ans+=s[i].pay;
		}
		else {
			ans+=s[i].val*d;
			break;
		}
	}
	printf("%.2f",ans);
	return 0;
}

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

用代码复习一下二叉树的3种遍历

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

struct TreeNode {
    char val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(char x) : val(x), left(nullptr), right(nullptr) {}
};

// 前序遍历:根 左 右
void preorder(TreeNode* root) {
    if (root == nullptr) return;
    cout << root->val << " ";
    preorder(root->left);
    preorder(root->right);
}

// 中序遍历:左 根 右
void inorder(TreeNode* root) {
    if (root == nullptr) return;
    inorder(root->left);
    cout << root->val << " ";
    inorder(root->right);
}

// 后序遍历:左 右 根
void postorder(TreeNode* root) {
    if (root == nullptr) return;
    postorder(root->left);
    postorder(root->right);
    cout << root->val << " ";
}

int main() {
    /*
            A
           / \
          B   C
         / \   \
        D   E   F
    */

    TreeNode* A = new TreeNode('A');
    TreeNode* B = new TreeNode('B');
    TreeNode* C = new TreeNode('C');
    TreeNode* D = new TreeNode('D');
    TreeNode* E = new TreeNode('E');
    TreeNode* F = new TreeNode('F');

    A->left = B;
    A->right = C;
    B->left = D;
    B->right = E;
    C->right = F;

    cout << "前序遍历: ";
    preorder(A);
    cout << "\n";

    cout << "中序遍历: ";
    inorder(A);
    cout << "\n";

    cout << "后序遍历: ";
    postorder(A);
    cout << "\n";

    return 0;
}

题解

普通BST:左<根<=右

镜像BST:左>=根>右

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;
vector<int>tree;//前序(根左右)
vector<int>ans;//后序(左右根) 
bool dfs(int left,int right,bool mirror){
	if(left>right)return true;
	int root=tree[left];
	int i=left+1;
	//正常 
	if(!mirror){
		while(i<=right&&tree[i]<root)i++;//左 
		int mid=i;
		while(i<=right&&tree[i]>=root)i++;//右 
		if(i<=right)return false;
		//若左右子树不合法则整棵树不合法 
		if(!dfs(left+1,mid-1,false))return false;
		if(!dfs(mid,right,false))return false;
	}
	//镜像
	else{
		while(i<=right&&tree[i]>=root)i++;
		int mid=i;
		while(i<=right&&tree[i]<root)i++;
		if(i<=right)return false;
		if(!dfs(left+1,mid-1,true))return false;
		if(!dfs(mid,right,true))return false;
	} 
	ans.push_back(root);
	return true;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n;
	tree.resize(n);
	for(int i=0;i<n;i++)cin>>tree[i];
	if(dfs(0,n-1,false))cout<<"YES"<<'\n';
	else {
		ans.clear();
		if(dfs(0,n-1,true))cout<<"YES"<<'\n';
		else {
			cout<<"NO"<<'\n';
			return 0;
		}
	}
	for(int i=0;i<ans.size();i++){
		if(i)cout<<" ";
		cout<<ans[i];
	}
	return 0;
}

L2-005 集合相似度

交集和并集

可以用两个哈希表记录

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;
vector<vector<int>>nums;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n;
	nums.resize(n+1);
	for(int i=1;i<=n;i++){
		int k;cin>>k;
		nums[i].resize(k);
		for(int j=0;j<k;j++)cin>>nums[i][j];
	}
	int t;cin>>t;
	while(t--){
		int a,b;
		cin>>a>>b;
		unordered_map<int,int>mapA;
		int cnt=0;
		unordered_map<int,int>mapAB;
		for(int i=0;i<nums[a].size();i++){
			mapA[nums[a][i]]++;
			mapAB[nums[a][i]]++;
		}
		for(int i=0;i<nums[b].size();i++){
			mapAB[nums[b][i]]++;
			if(mapA[nums[b][i]]){
				cnt++;
				mapA[nums[b][i]]=0;
			}
		}
		double ans=100.0*(double)cnt/(double)mapAB.size();
		printf("%.2f%\n",ans);
	}
	return 0;
}

L2-006 树的遍历

后序遍历的最后一个结点一定是当前子树的根

有点难,目前理解不了

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
struct Node{
	int houleft,houright;
	int zhongleft,zhongright;
};
int n;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n;
	vector<int>hou(n),zhong(n);
	for(int i=0;i<n;i++)cin>>hou[i];
	for(int i=0;i<n;i++)cin>>zhong[i];
	queue<Node>q;
	q.push({0,n-1,0,n-1});
	bool first=true;
	while(!q.empty()){
		auto cur=q.front();
		q.pop();
		int houleft=cur.houleft,houright=cur.houright;
		int zhongleft=cur.zhongleft,zhongright=cur.zhongright;
		if(houleft>houright)continue;
		int root=hou[houright];
		if(!first)cout<<" ";
		cout<<root;
		first=false;
		int k=zhongleft;
		while(k<=zhongright&&zhong[k]!=root)k++;
		int leftNum=k-zhongleft;
		int rightNum=zhongright-k;
		if(leftNum)q.push({houleft,houleft+leftNum-1,zhongleft,k-1});
		if(rightNum)q.push({houleft+leftNum,houright-1,k+1,zhongright});
	}
	return 0;
}

L2-007 家庭房产

感觉是一道并查集的大模拟,写的很难受

可以画一张家庭关系图谱来理解题意

并查集建立家庭关系

哈希表统计家庭房产

新建数组用于排序

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int MAXID=10005;
int n;
int parent[MAXID];
bool vis[MAXID];
double house[MAXID];
double area[MAXID];
struct Node{
	int minID=MAXID;
	int people=0;
	double sumhouse=0;
	double sumarea=0;
};
struct family{
	int minID;
	int people;
	double avghouse;
	double avgarea;
};
void add(int x){
	if(x==-1)return ;
	if(!vis[x]){
		vis[x]=true;
		parent[x]=x;
	}
}
int find(int x){
	if(parent[x]==x)return x;
	return parent[x]=find(parent[x]);
}
void unite(int a,int b){
	if(a==-1||b==-1)return ;
	int ra=find(a);
	int rb=find(b);
	if(ra!=rb)parent[ra]=rb;
}
bool com(const family &a,const family &b){
	if(a.avgarea!=b.avgarea)return a.avgarea>b.avgarea;
	else return a.minID<b.minID;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	for(int i=0;i<MAXID;i++)parent[i]=i;
	cin>>n;
	for(int i=0;i<n;i++){
		int id,father,mother,k;cin>>id>>father>>mother>>k;
		add(id);add(father);add(mother);
		unite(id,father);unite(id,mother);
		while(k--){
			int child;cin>>child;
			add(child);
			unite(id,child);
		}
		int cnt;
		double ar;
		cin>>cnt>>ar;
		house[id]+=cnt;
		area[id]+=ar;
	}
	unordered_map<int,Node>map;
	for(int i=0;i<MAXID;i++){
		if(!vis[i])continue;
		int r=find(i);
		map[r].people++;
		map[r].minID=min(map[r].minID,i);
		map[r].sumhouse+=house[i];
		map[r].sumarea+=area[i];
	}
	vector<family>ans;
	for(auto &t:map){
		Node &s=t.second;
		ans.push_back({s.minID,s.people,s.sumhouse/s.people,s.sumarea/s.people});
	}
	sort(ans.begin(),ans.end(),com);
	printf("%d\n",ans.size());
	for(int i=0;i<ans.size();i++){
		printf("%04d %d %.3f %.3f\n",ans[i].minID,ans[i].people,ans[i].avghouse,ans[i].avgarea);
	}
	return 0;
}

L2-008 最长对称子串

依次遍历字符来寻找对称字串

注意奇数和偶数长度的回文都要处理

例如:奇数:abcba

偶数:abccba

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	string s;
	getline(cin,s);
	int maxlen=1;
	for(int i=0;i<s.size();i++){
		int left=i;
		int right=i;
		while(left-1>=0&&right+1<s.size()&&s[left-1]==s[right+1]){
			left--;
			right++;
		}
		maxlen=max(maxlen,right-left+1);
		left=i;
		right=i+1;
		while(left>=0&&right<s.size()&&s[left]==s[right]){
			left--;
			right++;
		}
		maxlen=max(maxlen,right-left-1);
	} 
	cout<<maxlen;
	return 0;
}

L2-009 抢红包

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;
bool com(const vector<int>&x,vector<int>&y){
	if(x[0]!=y[0])return x[0]>y[0];
	else return x[1]>y[1];
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n;
	vector<vector<int>>s(n,vector<int>(3));
	for(int i=0;i<n;i++){
		s[i][2]=i;
		int k;cin>>k;
		while(k--){
			int a,b;cin>>a>>b;
			a--;
			s[i][0]-=b;
			s[a][0]+=b;
			s[a][1]++;
		}
	}
	sort(s.begin(),s.end(),com);
	for(int i=0;i<n;i++){
		printf("%d %.2f\n",s[i][2]+1,(double)s[i][0]/100.0);
	}
	return 0;
}

L2-053 算式拆解

树的后序遍历

L2-054 三点共线

这道题有点卡常

x1+x2=2*x3

哈希表模拟

用以下方法可以拿19/25分

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;
struct Node{
	int x1,y1;
	int x2,y2;
	int x3,y3;
};
bool com(const Node &x,const Node &y){
	if(x.x2!=y.x2)return x.x2<y.x2;
	else return x.x1<y.x1;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n;
	unordered_map<int,int>mapA;
	unordered_map<int,int>mapB;
	unordered_map<int,int>mapC;
	int a,b;
	for(int i=0;i<n;i++){
		cin>>a>>b;
		if(b==0)mapA[a]++;
		else if(b==1)mapB[a]++;
		else if(b==2)mapC[a]++;
	}
	vector<Node>ans;
	for(auto &[x1,y1]:mapA){
		for(auto &[x2,y2]:mapB){
			int x3=2*x2-x1;
			if(mapC.count(x3)){
				ans.push_back({x1,0,x2,1,x3,2});
			}
		}
	} 
	sort(ans.begin(),ans.end(),com);
	if(ans.empty())cout<<-1;
	else {
		for(Node &t:ans){
			printf("[%d, %d] [%d, %d] [%d, %d]\n",t.x1,t.y1,t.x2,t.y2,t.x3,t.y3);
		}
	}
	return 0;
}

优化:找出比较小的两个map,可以拿21/25分,还有4分TLE

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
struct Node{
	int x1,y1;
	int x2,y2;
	int x3,y3;
};
bool com(const Node &x,const Node &y){
	if(x.x2!=y.x2)return x.x2<y.x2;
	else return x.x1<y.x1;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n;
	unordered_map<int,int>mapA;
	unordered_map<int,int>mapB;
	unordered_map<int,int>mapC;
	int a,b;
	for(int i=0;i<n;i++){
		cin>>a>>b;
		if(b==0)mapA[a]++;
		else if(b==1)mapB[a]++;
		else if(b==2)mapC[a]++;
	}
	vector<Node>ans;
	int A=mapA.size()*mapB.size();
	int B=mapA.size()*mapC.size();
	int C=mapB.size()*mapC.size();
	if(A<=B&&A<=C){
		for(auto &[x1,y1]:mapA){
			for(auto &[x2,y2]:mapB){
				int x3=2*x2-x1;
				if(mapC.count(x3)){
					ans.push_back({x1,0,x2,1,x3,2});
				}
			}
		} 
	}
	else if(B<=A&&B<=C){
		for(auto &[x1,y1]:mapA){
			for(auto &[x3,y3]:mapC){
				if((x1+x3)%2)continue;
				int x2=(x1+x3)/2;
				if(mapB.count(x2)){
					ans.push_back({x1,0,x2,1,x3,2});
				}
			}
		} 
	}
	else {
		for(auto &[x2,y2]:mapB){
			for(auto &[x3,y3]:mapC){
				int x1=2*x2-x3;
				if(mapA.count(x1)){
					ans.push_back({x1,0,x2,1,x3,2});
				}
			}
		} 
	}
	sort(ans.begin(),ans.end(),com);
	if(ans.empty())cout<<-1;
	else {
		for(Node &t:ans){
			printf("[%d, %d] [%d, %d] [%d, %d]\n",t.x1,t.y1,t.x2,t.y2,t.x3,t.y3);
		}
	}
	return 0;
}

优化:用数组模拟哈希表

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int OFFSET=1000000;
const int MAXV=2000001;
int n;
struct Node{
	int x1,y1;
	int x2,y2;
	int x3,y3;
};
bool com(const Node &x,const Node &y){
	if(x.x2!=y.x2)return x.x2<y.x2;
	else return x.x1<y.x1;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n;
	vector<char>A(MAXV);
	vector<char>B(MAXV);
	vector<char>C(MAXV);
	int a,b;
	for(int i=0;i<n;i++){
		cin>>a>>b;
		if(b==0)A[a+OFFSET]=1;
		else if(b==1)B[a+OFFSET]=1;
		else if(b==2)C[a+OFFSET]=1;
	}
	vector<int>mapA;
	vector<int>mapB;
	vector<int>mapC;
	for(int i=0;i<MAXV;i++){
    	if(A[i]) mapA.push_back(i - OFFSET);
	}
	for(int i=0;i<MAXV;i++){
	    if(B[i]) mapB.push_back(i - OFFSET);
	}
	for(int i=0;i<MAXV;i++){
	    if(C[i]) mapC.push_back(i - OFFSET);
	}
	vector<Node>ans;
	for(int x1:mapA){
		for(int x2:mapB){
			int x3=2*x2-x1;
			if (x3 < -1000000 || x3 > 1000000) continue;
			if(C[x3 + OFFSET]){
				ans.push_back({x1,0,x2,1,x3,2});
			}
		}
	} 
	sort(ans.begin(),ans.end(),com);
	if(ans.empty())cout<<-1;
	else {
		for(Node &t:ans){
			printf("[%d, %d] [%d, %d] [%d, %d]\n",t.x1,t.y1,t.x2,t.y2,t.x3,t.y3);
		}
	}
	return 0;
}

L2-055 胖达的山头

一开始用的贪心,有几个测试点TLE了,拿了14/25分

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;
int ans;
string a,b;
bool com(const pair<int,int>&x,const pair<int,int>&y){
	return x.second<y.second;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n;
	vector<pair<int,int>>time;
	unordered_map<int,int>map;
	vector<bool>vis(n);
	for(int i=0;i<n;i++){
		cin>>a>>b;
		int start=3600*stoi(a.substr(0,2))+60*stoi(a.substr(3,2))+stoi(a.substr(6,2));
		int end=3600*stoi(b.substr(0,2))+60*stoi(b.substr(3,2))+stoi(b.substr(6,2));
		time.push_back({start,end});
	}
	sort(time.begin(),time.end(),com); 
	while(map.size()<n){
		ans++;
		int end=0;
		for(int i=0;i<n;i++){
			if(!vis[i]&&end<time[i].first){
				vis[i]=true;
				map[i]++;
				end=time[i].second;
			}
		}
	}
	cout<<ans;
	return 0;
}

优化:小根堆贪心

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int n;
string a, b;

int toSec(const string& s) {
    return 3600 * stoi(s.substr(0, 2))
         + 60 * stoi(s.substr(3, 2))
         + stoi(s.substr(6, 2));
}

bool com(const pair<int,int>& x, const pair<int,int>& y) {
    if (x.first != y.first) return x.first < y.first;  // 按开始时间排序
    return x.second < y.second;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n;
    vector<pair<int,int>> time;

    for (int i = 0; i < n; i++) {
        cin >> a >> b;
        int start = toSec(a);
        int end = toSec(b);
        time.push_back({start, end});
    }

    sort(time.begin(), time.end(), com);

    // 小根堆,存每个山头当前最后一只熊猫的结束时间
    priority_queue<int, vector<int>, greater<int>> pq;

    for (int i = 0; i < n; i++) {
        int start = time[i].first;
        int finish = time[i].second;

        // 题目是闭区间,所以只有 pq.top() < start 才能复用
        if (!pq.empty() && pq.top() < start) {
            pq.pop();
        }
        pq.push(finish);
    }

    cout << pq.size() << '\n';
    return 0;
}

当然,最优解是区间最大重叠数(扫描线或差分数组)

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;
string a,b;
int ans;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n;
	vector<int>diff(86401);
	for(int i=0;i<n;i++){
		cin>>a>>b;
		int start=3600*stoi(a.substr(0,2))+60*stoi(a.substr(3,2))+stoi(a.substr(6,2));
		int end=3600*stoi(b.substr(0,2))+60*stoi(b.substr(3,2))+stoi(b.substr(6,2));
		diff[start]++;
		diff[end+1]--;
	}
	int tem=0;
	for(int i=0;i<86401;i++){
		tem+=diff[i];
		ans=max(ans,tem);
	}
	cout<<ans; 
	return 0;
}

L2-056 被n整除的n位数

如果一一列举,时间复杂度为1e15

考虑用DFS构造

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
vector<int>ans;
int n,a,b;
void dfs(int pos,int cur){
	if(pos==n){
		if(cur>=a&&cur<=b)ans.push_back(cur);
		return;
	}
	for(int i=0;i<=9;i++){
		int next=cur*10+i;
		if(next%(pos+1)==0)dfs(pos+1,next);
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n>>a>>b;
	for(int i=1;i<=9;i++){
		dfs(1,i);
	}
	if(ans.size()){
		for(int i=0;i<ans.size();i++)cout<<ans[i]<<'\n';
	}
	else cout<<"No Solution";
	return 0;
}
相关推荐
EllinY2 小时前
扩展欧几里得算法 exgcd 详解
c++·笔记·数学·算法·exgcd
AI科技星2 小时前
三维网格—素数对偶性及其严格证明(全域数学·统一基态演化版)
算法·数学建模·数据挖掘
诸葛务农2 小时前
光电对抗:多模复合制导烟雾干扰外场试验及仿真(4)
人工智能·算法·光电对抗
WolfGang0073212 小时前
代码随想录算法训练营 Day39 | 动态规划 part12
算法·动态规划
阿Y加油吧3 小时前
动态规划经典题解:最长递增子序列 & 乘积最大子数组
算法·动态规划·代理模式
f3iiish3 小时前
3783. 整数的镜像距离 力扣
算法·leetcode
Not Dr.Wang4223 小时前
基于matlab的控制系统奈氏图及其稳定性分析
数据结构·算法·matlab
闻缺陷则喜何志丹3 小时前
【排序 离散化 二维前缀和】 P7149 [USACO20DEC] Rectangular Pasture S|普及+
c++·算法·排序·离散化·二维前缀和
rainbow7242443 小时前
AI学习路线分享:通用型认证与算法认证学习体验对比
人工智能·学习·算法