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=%E5%8D%A1%E7%89%87
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=%E5%9B%9E%E6%96%87%E6%97%A5%E6%9C%9F
6.既约分数
https://www.lanqiao.cn/problems/593/learning/?page=1&first_category_id=1&second_category_id=3&name=%E6%97%A2%E7%BA%A6%E5%88%86%E6%95%B0
7.数的分解
https://www.lanqiao.cn/problems/606/learning/?page=1&first_category_id=1&second_category_id=3&name=%E6%95%B0%E7%9A%84%E5%88%86%E8%A7%A3
8.九宫幻方
https://www.lanqiao.cn/problems/100/learning/?page=1&first_category_id=1&second_category_id=3&name=%E4%B9%9D%E5%AE%AB%E5%B9%BB%E6%96%B9

区间嵌套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

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

#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=%E5%8D%A1%E7%89%87

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

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

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

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

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

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

思路:暴力模拟

#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

思路:树状数组+离散化

#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。

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

#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=%E5%9B%9E%E6%96%87%E6%97%A5%E6%9C%9F

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 型的回文日期。

#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=%E6%97%A2%E7%BA%A6%E5%88%86%E6%95%B0

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

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

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

#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=%E6%95%B0%E7%9A%84%E5%88%86%E8%A7%A3

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

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

#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=%E4%B9%9D%E5%AE%AB%E5%B9%BB%E6%96%B9

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

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

4 9 2

3 5 7

8 1 6

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

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

输入描述

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

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

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

输出描述

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

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

#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;
		}
	}
}
  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值