目录
[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;
}