2.14学习总结

1.区间嵌套

https://www.acwing.com/problem/content/description/5462/

2.卡片

https://www.lanqiao.cn/problems/1443/learning/?page=1\&first_category_id=1\&second_category_id=3\&name=卡片

3.逆序对https://www.luogu.com.cn/problem/P1908

4.合唱队形

https://www.luogu.com.cn/problem/P1091

5.回文日期

https://www.lanqiao.cn/problems/498/learning/?page=1\&first_category_id=1\&second_category_id=3\&name=回文日期

6.既约分数

https://www.lanqiao.cn/problems/593/learning/?page=1\&first_category_id=1\&second_category_id=3\&name=既约分数

7.数的分解

https://www.lanqiao.cn/problems/606/learning/?page=1\&first_category_id=1\&second_category_id=3\&name=数的分解

8.九宫幻方

https://www.lanqiao.cn/problems/100/learning/?page=1\&first_category_id=1\&second_category_id=3\&name=九宫幻方

区间嵌套https://www.acwing.com/problem/content/description/5462/

给定 n� 个正整数区间,编号 1∼n1∼�。

其中,第 i� 个区间为 [li,ri][��,��]。

请你找到一对不同的整数 j,k�,�(1≤j,k≤n1≤�,�≤�),使得区间 j� 完全包含于区间 k�。

如果 lj≥lk��≥�� 且 rj≤rk��≤��,则区间 j� 完全包含于区间 k�。

输入格式

第一行包含整数 n�。

接下来 n� 行,其中第 i� 行包含两个整数 li,ri��,��。

输出格式

如果题目无解,则输出一行 -1 -1

否则,在一行内输出一对不同的整数 j,k�,�,满足区间 j� 完全包含于区间 k�。

如果答案不唯一,则输出任意合理答案均可。

数据范围

前 66 个测试点满足 1≤n≤51≤�≤5。

所有测试点满足 1≤n≤3×1051≤�≤3×105,1≤li≤ri≤1091≤��≤��≤109。

输入样例1:
复制代码
5
1 10
2 9
3 9
2 3
2 9
输出样例1:
复制代码
2 1
输入样例2:
复制代码
3
1 5
2 6
6 20
输出样例2:
复制代码
-1 -1

思路:按照左区间从大到小排序,然后比较相邻节点的右区间大小

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
#define INF 0x3f3f3f3f

const int N=3e5+5;

struct node{
	int l;
	int r;
	int idx;
};

node e[N];
bool cmp(const node&a ,const node &b){
	if (a.l==b.l) return a.r>b.r;
	else return a.l<b.l;
}
signed main(){
	int n;
	cin>>n;
	for (int i=1;i<=n;++i){
		cin>>e[i].l>>e[i].r;
		e[i].idx=i;
	}
	sort(e+1,e+1+n,cmp);
	for (int i=1;i<n;++i){
	    if (e[i].r>=e[i+1].r){
	        cout<<e[i+1].idx<<" "<<e[i].idx;
	        return 0;
	    }
	}
	cout<<-1<<" "<<-1;
	return 0;
}
卡片

https://www.lanqiao.cn/problems/1443/learning/?page=1\&first_category_id=1\&second_category_id=3\&name=卡片

小蓝有很多数字卡片,每张卡片上都是数字 00 到 99。

小蓝准备用这些卡片来拼一些数,他想从 11 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。

小蓝想知道自己能从 11 拼到多少。

例如,当小蓝有 3030 张卡片,其中 00 到 99 各 33 张,则小蓝可以拼出 11 到 1010,

但是拼 1111 时卡片 11 已经只有一张了,不够拼出 1111。

现在小蓝手里有 00 到 99 的卡片各 20212021 张,共 2021020210 张,请问小蓝可以从 11 拼到多少?

思路:暴力模拟

cpp 复制代码
#include <iostream>
using namespace std;
int a[10];
void cc(int b){
  while (b>0){
    a[b%10]++;
    b/=10;
  }
}
bool check(){
  for (int i=0;i<10;++i){
    if (a[i]>2021)return true;
  }
  return false;
}
int main()
{
  for (int i=1;i<=4400;++i){
    cc(i);
    if (check()){
      cout<<i-1;
      return 0;
    }
  }
  return 0;
}
逆序对https://www.luogu.com.cn/problem/P1908

题目描述

猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。

最近,TOM 老猫查阅到一个人类称之为"逆序对"的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 ��>��ai​>aj​ 且 �<�i<j 的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。

Update:数据已加强。

输入格式

第一行,一个数 �n,表示序列中有 �n个数。

第二行 �n 个数,表示给定的序列。序列中每个数字不超过 109109。

输出格式

输出序列中逆序对的数目。

输入输出样例

输入 #1复制

6

5 4 2 6 3 1

输出 #1复制

11

说明/提示

对于 25%25% 的数据,�≤2500n≤2500

对于 50%50% 的数据,�≤4×104n≤4×104。

对于所有数据,�≤5×105n≤5×105

思路:树状数组+离散化

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
#define INF 0x3f3f3f3f

const int N=5e5+5;
int n,Rank[N],tree[N];

struct node{
	int val;
	int num;
}a[N];

bool cmp(const node& a, const node& b){
	if (a.val==b.val) return a.num<b.num;
	return a.val<b.val;
}

void update(int x,int c){
	while (x<=N){
		tree[x]+=c;
		x+=lowbit(x);
	}
}

int query(int x){
	int res=0;
	while (x>0){
		res+=tree[x];
		x-=lowbit(x);
	}
	return res;
}

signed main(){
	cin>>n;
	for (int i=1;i<=n;++i){
		cin>>a[i].val;
		a[i].num=i;
	}
	sort(a+1,a+1+n,cmp);
	for (int i=1;i<=n;++i){
		Rank[a[i].num]=i;
	}
	int sum=0;
	for (int i=n;i>0;--i){
		update(Rank[i],1);
		sum+=query(Rank[i]-1);
	}
	cout<<sum;
}
合唱队形https://www.luogu.com.cn/problem/P1091

题目描述

�n 位同学站成一排,音乐老师要请其中的 �−�n−k 位同学出列,使得剩下的 �k 位同学排成合唱队形。

合唱队形是指这样的一种队形:设 �k 位同学从左到右依次编号为 1,2,1,2, ... ,�,k,他们的身高分别为 �1,�2,t1​,t2​, ... ,��,tk​,则他们的身高满足 �1<⋯<��>��+1>t1​<⋯<ti​>ti+1​> ... >��(1≤�≤�)>tk​(1≤i≤k)。

你的任务是,已知所有 �n 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入格式

共二行。

第一行是一个整数 �n(2≤�≤1002≤n≤100),表示同学的总数。

第二行有 �n 个整数,用空格分隔,第 �i 个整数 ��ti​(130≤��≤230130≤ti​≤230)是第 �i 位同学的身高(厘米)。

输出格式

一个整数,最少需要几位同学出列。

输入输出样例

输入 #1复制

8

186 186 150 200 160 130 197 220

输出 #1复制

4

说明/提示

对于 50%50% 的数据,保证有 �≤20n≤20。

对于全部的数据,保证有 �≤100n≤100。

思路:动态规划,找最长单增子串,从左往右和从右往左都要遍历,然后重新遍历数组最高点,找到结果

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
#define INF 0x3f3f3f3f

int dp1[105],dp2[105];
int n,a[105];

signed main(){
	cin>>n;
	for (int i=1;i<=n;++i) cin>>a[i];
	for (int i=1;i<=n;++i){
		dp1[i]=1;
		dp2[i]=1;
	}
	for (int i=1;i<=n;++i){
		for (int j=1;j<i;++j){
			if (a[j]<a[i]) dp1[i]=max(dp1[i],dp1[j]+1);
		}
	}
	for (int i=n;i>=1;--i){
		for (int j=n;j>i;--j){
			if (a[j]<a[i]) dp2[i]=max(dp2[i],dp2[j]+1);
		}
	}
	int res=0;
	for (int i=1;i<=n;++i){
		res=max(res,(dp1[i]+dp2[i]-1));
	}
	cout<<n-res;
}
回文日期

https://www.lanqiao.cn/problems/498/learning/?page=1\&first_category_id=1\&second_category_id=3\&name=回文日期

2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 "yyyymmdd" 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。

有人表示 20200202 是 "千年一遇" 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。

也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 "千年一遇",顶多算 "千年两遇"。

给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。

输入描述

输入包含一个八位整数 �N,表示日期。

对于所有评测用例,10000101≤�≤8999123110000101≤N≤89991231,保证 �N 是一个合法日期的 8 位数表示。

输出描述

输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
#define INF 0x3f3f3f3f

int days[13]={-1,31,28,31,30,31,30,31,31,30,31,30,31};

string check(int date){
  string s=to_string(date),t=to_string(date);
  reverse(t.begin(),t.end());
  s+=t;
  int y=stoi(s.substr(0,4)),m=stoi(s.substr(4,2)),d=stoi(s.substr(6,2));
  if (y%400==0 || (y%4==0 && y%100!=0)) days[2]=29;
  else days[2]=28;
  if (m<1 || m>12 || d>days[m] || d<1) return "-1";
  return s;
}

string check2(int date){
  string s=to_string(date),t=to_string(date);
  reverse(t.begin(),t.end());
  s+=t;
  if (s[0]==s[2] && s[1]==s[3]) return s;
  return "-1";
}

signed main(){
  int date;
  cin>>date;
  string ans=" ";
  for (int i=date/10000;;++i){
    if (check(i)=="-1" || check(i)==to_string(date)) continue;
    if (ans==" ") ans=check(i);
    if (check2(i)!="-1"){
      cout<<ans<<endl<<check2(i);
      return 0;
    }
  }
}
既约分数

https://www.lanqiao.cn/problems/593/learning/?page=1\&first_category_id=1\&second_category_id=3\&name=既约分数

如果一个分数的分子和分母的最大公约数是 11,这个分数称为既约分数。

例如 34,18,7143​,81​,17​, 都是既约分数。

请问,有多少个既约分数,分子和分母都是 11 到 20202020 之间的整数(包括 11 和 20202020)?

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
#define INF 0x3f3f3f3f

int gcd(int a,int b){
	if (b==0) return a;
	return gcd(b,a%b);
}

signed main(){
	int cnt=0;
	for (int i=1;i<=2020;++i){
		for (int j=1;j<=2020;++j){
			if (gcd(i,j)==1) cnt++;
		}
	}
	cout<<cnt;
}
 
数的分解

https://www.lanqiao.cn/problems/606/learning/?page=1\&first_category_id=1\&second_category_id=3\&name=数的分解

把 20192019 分解成 33 个各不相同的正整数之和,并且要求每个正整数都不包含数字 22 和 44,一共有多少种不同的分解方法?

注意交换 33 个整数的顺序被视为同一种方法,例如 1000+1001+181000+1001+18 和 1001+1000+181001+1000+18 被视为同一种。

cpp 复制代码
#include <iostream>
using namespace std;

bool hefa(int a){
  while (a>0){
    int m=a%10;
    a/=10;
    if (m==2 || m==4) return false;
  }
  return true;
}

int main()
{
  int cnt=0;
  for(int i=1;i<=2019;++i){
    for (int j=i+1;j<2019-i-j;++j){
          if (hefa(i) && hefa(j) && hefa(2019-i-j)){
            cnt++;
          }
      }
    }
  cout<<cnt;
  return 0;
}
九宫幻方

https://www.lanqiao.cn/problems/100/learning/?page=1\&first_category_id=1\&second_category_id=3\&name=九宫幻方

小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将 1~9 不重复的填入一个 3*3 的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。

三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:"二四为肩,六八为足,左三右七,戴九履一,五居其中",通过这样的一句口诀就能够非常完美的构造出一个九宫格来。

4 9 2

3 5 7

8 1 6

有意思的是,所有的三阶幻方,都可以通过这样一个九宫格进行若干镜像和旋转操作之后得到。现在小明准备将一个三阶幻方(不一定是上图中的那个)中的一些数抹掉,交给邻居家的小朋友来进行还原,并且希望她能够判断出究竟是不是只有一个解。

而你呢,也被小明交付了同样的任务,但是不同的是,你需要写一个程序。

输入描述

输入仅包含单组测试数据。

每组测试数据为一个 3*3 的矩阵,其中为 0 的部分表示被小明抹去的部分。

给出的矩阵至少能还原出一组可行的三阶幻方。

输出描述

如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出"Too Many"(不包含引号)。

思路:DFS找空格内的字符,然后判断是否可以

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
#define INF 0x3f3f3f3f
int n=0;
int a[10][10],ans[10][10],vis[10],cnt=0;
pair<int,int>p[10];
bool check(){
	int p=a[1][1]+a[3][3]+a[2][2];
	for (int i=1;i<=3;++i){
		int m=0,c=0;
		for (int j=1;j<=3;++j){
			m+=a[i][j];
			c+=a[j][i];
		}
		if (m!=p|| c!=p) return false;
	}
	if (p!=a[1][3]+a[2][2]+a[3][1]) return false;
	return true;
}

void dfs(int now){
	if (now>n){
		if(check()){
			cnt++;
			for (int i=1;i<=3;++i){
				for (int j=1;j<=3;++j){
					ans[i][j]=a[i][j];
				}
			}
		}
		return ;
	}
	int x=p[now].first,y=p[now].second;
	for (int k=1;k<=9;++k){
		if (vis[k]) continue;
		a[x][y]=k;
		vis[k]=1;
		dfs(now+1);
		a[x][y]=0;
		vis[k]=0;
	}
}

signed main(){
	for (int i=1;i<=3;++i){
		for (int j=1;j<=3;++j){
			cin>>a[i][j];
			if (!a[i][j]) p[++ n]=make_pair(i,j);
			vis[a[i][j]]=1;
		}
	}
	dfs(1);
	if (cnt!=1){
		cout<<"Too Many";
		return 0;
	}else if (cnt==1){
		for (int i=1;i<=3;++i){
			for (int j=1;j<=3;++j){
				cout<<ans[i][j]<<" ";
			}
			cout<<endl;
		}
	}
}
相关推荐
西岸行者3 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意3 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码3 天前
嵌入式学习路线
学习
毛小茛3 天前
计算机系统概论——校验码
学习
babe小鑫3 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms3 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下3 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。3 天前
2026.2.25监控学习
学习
im_AMBER3 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J3 天前
从“Hello World“ 开始 C++
c语言·c++·学习