蓝桥冲刺31天打卡—Day6

目录

1、🌙巧排扑克牌

题目描述

思路

2、🌍质数拆分

题目描述

 思路:

AC代码

3、✏️日志统计

题目描述

思路

 AC代码

 4、💊 递增三元组

思路 

AC代码 

5、📕外卖店优先级

题目描述

思路

AC代码


1、🌙巧排扑克牌

巧排扑克牌

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

小明刚上小学,学会了第一个扑克牌“魔术”,到处给人表演。魔术的内容是这样的:

他手里握着一叠扑克牌:A,2,....J,Q,K一共 1313 张。他先自己精心设计它们的顺序,然后正面朝下拿着,开始表演。

只见他先从最下面拿一张放到最上面,再从最下面拿一张翻开放桌子上,是 AA;然后再从最下面拿一张放到最上面,再从最下面拿一张翻开放桌子上,是 22;......如此循环直到手中只有一张牌,翻开放桌子上,刚好是 KK。

这时,桌上牌的顺序是:A,2,3,4,5,6,7,8,9,10,J,Q,K

请你计算一下,小明最开始的时候手里牌的顺序是怎样的。

把结果写出来,逗号分割,小明“魔术”开始时,最下面的那张牌输出为第一个数据。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

思路

暴力模拟题

题意是每轮取牌时先取最底下的牌放到第一个,再取出剩下的。

本题因为模拟所需次数较少,我是通过表格进行模拟操作做出来的。

注意:输出时各数间隔的逗号是英文字符的逗号且每个数字中间要有空格!! 

假设X1~X13为手牌顺序 正面朝下后顺序变为X13~X1

但是小明“魔术”开始时,最下面的那张牌输出为第一个数据

所以最后输出顺序为X13~X1

绿色代表置顶的牌,黄色代表取出放桌子的牌

每轮取牌

X13

X12

X11

X10

X9

X8

X7

X6

X5

X4

X3

X2

X1

X12=A

X11

X10

X9

X8

X7

X6

X5

X4

X3

X2

X1

X13

X10=2

X9

X8

X7

X6

X5

X4

X3

X2

X1

X13

X11

X8=3

X7

X6

X5

X4

X3

X2

X1

X13

X11

X9

X6=4

X5

X4

X3

X2

X1

X13

X11

X9

X7

X4=5

X3

X2

X1

X13

X11

X9

X7

X5

X2=6

X1

X13

X11

X9

X7

X5

X3

X13=7

X11

X9

X7

X5

X3

X1

X9=8

X7

X5

X3

X1

X11

X5=9

X3

X1

X11

X7

X1=10

X11

X7

X3

X7=J

X3

X11

X11=Q

X3

X3=K

 X13~X1="7, A, Q, 2, 8, 3, J, 4, 9, 5, K, 6, 10"

#include <iostream>
using namespace std;
int main()
{
  //cout<<"10,6,K,5,9,4,J,3,8,2,Q,A,7";
  //cout<<"7,A,Q,2,8,3,J,4,9,5,K,6,10";
  cout<<"7, A, Q, 2, 8, 3, J, 4, 9, 5, K, 6, 10";
  return 0;
}

答案

"7, A, Q, 2, 8, 3, J, 4, 9, 5, K, 6, 10"

2、🌍质数拆分

质数拆分

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

将 2019拆分为若干个两两不同的质数之和,一共有多少种不同的方法?

注意交换顺序视为同一种方法,例如 2 + 2017 = 2019 与 2017 + 2 = 2019 视为同一种方法。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

 思路:

第一次使用埃氏筛+暴力算,果断超时。

后面采用01背包后通过了(感谢y总的闫氏DP分析法)

暴力超时解法

#include <iostream>
#include <algorithm>

using namespace std;

const int N= 2020;
typedef long long ll;
ll primes[N], cnt;//primes存放质数,cnt质数个数
bool st[N];//判断是否为质数
//st[i], i为质数则为false否则为true
ll ans=0;//记录方法数



int main()
{
	for (int i = 2; i <=2019; i ++ )
	{
		if (st[i]) continue;
		primes[cnt ++ ] = i;//存放质数
		for (int j = i + i; j <=2019; j += i)
			st[j] = true;
	}
	for(int i=0;i<=cnt;i++){//遍历质数表
		int num=2019-primes[i];//判断2019与质数的差是否为质数
		if(!st[num]) ans++;
	}
	printf("%lld",ans/2);
	
	return 0;
}

闫氏DP分析法:
01背包:一、状态表示 f(i,j):集合:在前i个质数中能够构成和为j的方案

                                                属性:数量
               二、状态计算:集合划分:
                                         不含i的情况:f(i,j)=f(i-1,j);
                                         含i的情况:f(i,j)=f(i-1,j-prime[i])

                                                           (prime[i]为i所对应的质数)

当前背包容量够(j>=primes[i]),选第i个质数对应代码:f[i][j] = f[i - 1][j - primes[i]] 

当前背包容量不够(j<primes[i])因此选第 i 个质数即为选第 i−1质数

对应代码:f[i][j] = f[i - 1][j]

AC代码

#include <iostream>
#include <algorithm>

using namespace std;

const int N= 2100;
typedef long long ll;
int cnt=1;//便于背包问题计算
ll primes[N];//primes存放质数
bool st[N];//判断是否为质数
	       //st[i], i为质数则为false否则为true
ll ans=0;//记录方法数
ll f[N][N];//从前 i 个物品中选,且总体积恰好为 j 的方案的数量


int main()
{
	for (int i = 2; i <=2019; i ++ )//埃氏筛
	{
		if (st[i]) continue;
		primes[cnt ++ ] = i;//存放质数
		for (int j = i + i; j <=2019; j += i)
			st[j] = true;
	}
	/*for(int i=0;i<=cnt;i++){//遍历质数表
		int num=2019-primes[i];//2019与质数的差
		if(!st[num]) ans++;
	}*/
	//printf("%lld",ans/2);
	f[0][0]=1;//容量为0算一种方案
	for(int i=1;i<cnt;i++){
		for(int j=0;j<=2019;j++){//背包容积最小为0,所以j从0开始
			f[i][j]=f[i-1][j];//不选i
			if(j>=primes[i]){//背包能否装下条件判断
				f[i][j]+=f[i-1][j-primes[i]];//选i
			}
		}
	}
	cout<<f[cnt-1][2019]<<endl;
	
	return 0;
}

3、✏️日志统计

日志统计

题目描述

小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有 N 行。其中每一行的格式是:

ts\ idts id

表示在 ts 时刻编号 id 的帖子收到一个"赞"。

现在小明想统计有哪些帖子曾经是"热帖"。如果一个帖子曾在任意一个长度为 DD 的时间段内收到不少于 K 个赞,小明就认为这个帖子曾是"热帖"。

具体来说,如果存在某个时刻 T 满足该帖在 [T,T+D) 这段时间内(注意是左闭右开区间)收到不少于 K 个赞,该帖就曾是"热帖"。

给定日志,请你帮助小明统计出所有曾是"热帖"的帖子编号。

输入描述

输入格式:

第一行包含三个整数 N,D,K

以下 N 行每行一条日志,包含两个整数 ts 和 id。

范围:

1≤K≤N≤10^5 ,0≤ts,id≤10^5,1≤D≤10000

 输入

7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3

 输出

1
3

输出描述

按从小到大的顺序输出热帖 id。每个 id 一行。、

思路

暴力法又超时😭,看了y总视频的讲解后使用双指针算法
1、对所有的赞按照时间从小到大排序
2、通过双指针i,j维护长度不大于d的区间,记录该区间的中所有帖子获得的赞数
3、当两指针距离超过d时,赞失效。

双指针算法模板(来自acwing)

for (int i = 0, j = 0; i < n; i ++ )
{
    while (j < i && check(i, j)) j ++ ;

    // 具体问题的逻辑
}

 AC代码

/*
1、对所有的赞按照时间从小到大排序
2、通过双指针i,j维护长度不大于d的区间,记录该区间的中所有帖子获得的赞数*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+10 ;
#define x first 
#define y second 
typedef pair<int,int>PII;
int cnt[N];//储存每个id获得点赞数
bool st[N];//储存每个id是否是热帖
PII logs[N];//储存ts,id
int n,d,k;
int main(){
	cin>>n>>d>>k;
	for(int i=0;i<n;i++) cin>>logs[i].x>>logs[i].y;
	sort(logs,logs+n);//按时间顺序递增排序
	for (int i = 0, j = 0; i < n; i ++ )
	{
		int id=logs[i].y;//记录i时刻的id
		cnt[id]++;
		while (logs[i].x-logs[j].x>=d){//当两指针相隔距离超过d时,赞无效
			cnt[logs[j].y]--;
			j++;
		}
		if(cnt[id]>=k) st[id]=true;
    }
	for(int i=0;i<=100000;i++){
		if(st[i]) cout<<i<<endl;
	}
	return 0;
}

 4、💊 递增三元组

递增三元组

间限制:1.0s   内存限制:256.0MB

  给定三个整数数组
  A = [A1, A2, ... AN],
  B = [B1, B2, ... BN],
  C = [C1, C2, ... CN],
  请你统计有多少个三元组(i, j, k) 满足:
  1. 1 <= i, j, k <= N
  2. Ai < Bj < Ck

输入格式

  第一行包含一个整数N。
  第二行包含N个整数A1, A2, ... AN。
  第三行包含N个整数B1, B2, ... BN。
  第四行包含N个整数C1, C2, ... CN。

  对于30%的数据,1 <= N <= 100
  对于60%的数据,1 <= N <= 1000
  对于100%的数据,1 <= N <= 100000 0 <= Ai, Bi, Ci <= 100000

输出格式

  一个整数表示答案

输入

3
1 1 1
2 2 2
3 3 3

输出

27 

思路 

直接暴力枚举Ai,Bj,Ck超时

使用二分进行优化,只枚举b,二分查找 a对于b数组小于b[i]的最大值c对于a数组大于a[i]的最小值,然后在根据下标找出a中有多少个数小于b[i]idx1,c中有多少个数大于b[i](idx2),

通过乘法原理可知  带有b[i]的合法选择数就是 idx1*idx2

注意:idx1,idx2,sum要用long long型

此题二分可使用STL函数 lower_bound 和 upper_bound

  •  lower_bound(nums, nums + n, val) - nums

lower_bound函数从nums数组 nums到nums+n的范围里中二分查找第一个大于等于val的数字,并返回此地址,通过返回的地址减去起始地址nums,得到找到数字在数组中的下标。

  • upper_bound(nums, nums + n, val) - nums

lower_bound函数从nums数组 nums到nums+n的范围里中二分查找第一个大于val的数字,并返回此地址,通过返回的地址减去起始地址nums,得到找到数字在数组中的下标。

AC代码 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+10 ;
int n;
int a[N],b[N],c[N];
ll sum;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
	for(int i=1;i<=n;i++) scanf("%d",&c[i]);
	//二分前先排序
	sort(a+1,a+1+n);
	sort(b+1,b+1+n);
	sort(c+1,c+1+n);
	for(int i=1;i<=n;i++){
		ll idx1=(lower_bound(a + 1, a + 1 + n, b[i]) - a) - 1;  //在a中找比b小的下标
		ll idx2=n - (upper_bound(c + 1, c + 1 + n, b[i]) - c) + 1; //在c中找比b大的下标
		sum+=idx1*idx2;
	}
	printf("%lld",sum);
	
	return 0;
}

5、📕外卖店优先级

外卖店优先级

题目描述

"饱了么"外卖系统中维护着 N 家外卖店,编号 1 ∼ N。每家外卖店都有 一个优先级,初始时 (0 时刻) 优先级都为 0。

每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减 到 0;而如果外卖店有订单,则优先级不减反加,每有一单优先级加 2。

如果某家外卖店某时刻优先级大于 5,则会被系统加入优先缓存中;如果 优先级小于等于 3,则会被清除出优先缓存。

给定 TT 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优 先缓存中?

输入描述

第一行包含 3 个整数 N,M,T

以下 M 行每行包含两个整数 ts,id,表示 tsts 时刻编号 id 的外卖店收到一个订单。

其中,

1≤N,M,T≤10^5  ,1≤ts≤T  ,1≤id≤N

输出描述

输出一个整数代表答案。

输入

2 6 6
1 1
5 2
3 1
6 2
2 1
6 2

输出

1

思路

 只会最暴力的做法(模拟题的细节也好烦。。。)这里放上y总的代码和思路

先根据时间,店号顺序对订单进行排序
将连续没有订单的时刻统一到下一次购买订单时或者t时刻集中处理
(只需考虑有订单的店,大幅度减少数据量)

score[i]表示第i个店铺当前优先级
last[i] 表示第i个店铺上一个有订单的时刻
st[i]表示当前店铺是否处于优先缓存中

AC代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 100010;

int n, m, T;
int score[N], last[N];
bool st[N];

PII order[N];

int main()
{
	scanf("%d%d%d", &n, &m, &T);
	for (int i = 0; i < m; i ++ ) scanf("%d%d", &order[i].x, &order[i].y);
	sort(order, order + m);
	
	for (int i = 0; i < m;)
	{
		int j = i;
		while (j < m && order[j] == order[i]) j ++ ;
		int t = order[i].x, id = order[i].y, cnt = j - i;
		i = j;
		
		score[id] -= t - last[id] - 1;
		if (score[id] < 0) score[id] = 0;
		if (score[id] <= 3) st[id] = false; // 以上处理的是t时刻之前的信息
		
		score[id] += cnt * 2;
		if (score[id] > 5) st[id] = true;
		
		last[id] = t;
	}
	
	for (int i = 1; i <= n; i ++ )
		if (last[i] < T)
	{
		score[i] -= T - last[i];
		if (score[i] <= 3) st[i] = false;
	}
	
	int res = 0;
	for (int i = 1; i <= n; i ++ ) res += st[i];
	
	printf("%d\n", res);
	
	return 0;
}

今天的题真够难的,好多题没有思路或者只会暴力😟😰

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月色美兮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值