蓝桥杯真题31日冲刺国一 | 每日题解报告 第六天

大家好,我是泡泡,今天题有点多,大家好好消化理解

目录

一、巧拼扑克牌

二、质数拆分

三、日志统计

四、递增三元组

五、外卖店优先级


一、巧拼扑克牌

题目链接:巧排扑克牌 - 蓝桥云课 (lanqiao.cn)

题目要求:

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

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

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

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

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

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

解题思路:手推题,直接模拟即可,不过我模拟了半天,恶心的水题,代码输出格式也卡。

先取出最下面一张放置上面,然后再翻开下面一张 最后得到一个升序排序的数字排列
?,A,?,2,?,3,?,4,?,5,?,6,? 后边大家也按照这个思路来就好,因为是手推的也讲不出太细了我(我太菜了)

//注意输出格式是,加空格
#include<bits/stdc++.h>
using namespace std;
int main()
{
  printf("7, A, Q, 2, 8, 3, J, 4, 9, 5, K, 6, 10");
  return 0;
}

二、质数拆分

题目链接:质数拆分 - 蓝桥云课 (lanqiao.cn)

题目要求:

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

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

解题思路:

01背包,从前 i 个物品中选,且总体积恰好为 j 的方案的数量。

​
#include<bits/stdc++.h>
using namespace std;
long long a[2020];
int p[2020];
bool pd(int x)
{
	if(x==1)
	{
		return false;
	}
	for(int i=2;i<=sqrt(x);i++)
	{
		if(x%i==0)
		{
			return false;
		}
	}
	return true;
}
int main()
{
    a[0]=1;
    int n=1;
    for(int i=1;i<2019;i++)
	{
        if(pd(i))
		{
            p[n++]=i;
        }
    }
    for(int i=1;i<=n-1;i++)
    {
        for(int j=2019;j>=p[i];j--)
        {
        	a[j] += a[j-p[i]];
		}
    }
    cout<<a[2019];
    return 0;
}

​

三、日志统计

题目链接:日志统计 - 蓝桥云课 (lanqiao.cn)

题目要求:

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

ts\ id

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

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

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

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

解题思路:

这是一个模拟题,定义一个结构体保存时间和id,然后排序,检查是否有赞,当前时间和上次时间是否超了区间,是否是热帖就好。

#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
int num[N];//赞
int flag[N];//是否是热帖
struct post{
    int id;
    int ts;
}p[N];
int cmp(post x,post y)
{
    return x.ts<y.ts;//越早的越在前
}
int main()
{
    int n,d,k;
    cin>>n>>d>>k;
    for(int i=0;i<n;i++)
    {
        cin>>p[i].ts>>p[i].id;
    }
    sort(p,p+n,cmp);//结构体排序
    for(int i=0,j=0;i<n;i++)
    {
        num[p[i].id]++;//点赞加一
        while(p[i].ts-p[j].ts>=d)//当前时间如果与上次时间相差过了d
        { 
            num[p[j].id]--;
            j++;//随着时间流逝,d之前的每个贴的次数都减1
        }
        if(num[p[i].id]>=k)
        {
            flag[p[i].id] = 1;//如果这个帖子的点赞超过k
        }
    }
    for(int i=0;i<N;i++)
    {
        if(flag[i])//如果是热帖输出id
        {
            cout<<i<<endl;
        }
    }
    return 0;
}

四、递增三元组

题目链接:“蓝桥杯”练习系统

题目要求:  

给定三个整数数组
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

解题思路:

我们给每个数组排序,然后使用二分查找函数查找a和b,b和c,每次加这两个找到的值相乘就可。

lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

#include<bits/stdc++h>
using namespace std;
long long n,aa,aaa,sum;
int a[100005],b[100005],c[100005];
int main()
{
   cin>>n;
   for(int i=0;i<n;i++)
   {
   	cin>>a[i];
   }
   for(int i=0;i<n;i++)
   {
   	cin>>b[i];
   }
   for(int i=0;i<n;i++)
   {
   	cin>>c[i];
   }
   sort(a,a+n);
   sort(b,b+n);
   sort(c,c+n);
   for(int i=0;i<n;i++)
   {
   	   aa=lower_bound(a,a+n,b[i])-a;
   	   aaa=n-(upper_bound(c,c+n,b[i])-c);
	   sum+=aa*aaa;
   }
while(1)
{
    cout<<sum;
}
//防抄袭
} 

五、外卖店优先级

题目链接:外卖店优先级 - 蓝桥云课 (lanqiao.cn)

题目要求:

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

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

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

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

解题思路:

模拟题,和第三题差不多,结构体排序,然后检查上一次订单与这一次的时间,判断优先缓存在不在加不加入。

#include<bits/stdc++.h>
using namespace std;
struct node{
    int ts,id;
}a[100001];
int val[100001];//得分
bool huan[100001];//优先缓存
int shang[100001];//上次订单时间
bool cmp(node a,node b)
{
    if(a.id==b.id)//id从小到大排,时间也是
    {
        return a.ts<b.ts;
    }
    return a.id<b.id;
}
int main()
{
    int n,m,t;
    cin>>m>>n>>t;
    for(int i=0;i<n;i++)
    {
        cin>>a[i].ts>>a[i].id;
    }
    sort(a,a+n,cmp);
    for(int i=0;i<n;i++)
    {
        int tt = a[i].ts,id = a[i].id;//tt是当前时间 id是当前店id
        if(tt!=shang[id])//如果当前时间与上次时间不同
        {
            val[id] -= tt - shang[id] - 1;//得分按情况减少
        }
        val[id] = max(val[id],0);//如果得分少于0 归0
        if(val[id]<=3)//如果得分低于等于3
        {
            huan[id] = false;//优先缓存取消
        }
        val[id] += 2;//得分增加
        if(val[id]>5)//如果得分大于5
        {
            huan[id] = true;//加入优先缓存
        }
        shang[id] = tt;//更新上次时间
    }
    for(int i=0;i<n;i++)//判断t时刻
    {
        if(shang[i]<t)//如果id为i的店最后一次订单时间小于t
        {
            val[i] -= t - shang[i];//得分减少
        }
        if(val[i]<=3)//优先缓存判断
        {
            huan[i] = false;
        }
    }
    int sum = 0;
    for(int i=0;i<n;i++)
    {
        if(huan[i])//如果店在优先缓存
        {
            sum++;
        }
    }
while(1)
{
    cout<<sum;
}
    return 0;//防抄袭
}

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论
题目描述: 给定一个由 n 个节点组成的树,每个节点都有一个权值。定义一个节点的权值为其子树中所有节点的权值之和。请你返回所有满足下列条件的节点的权值之和: 该节点位于树的重心以上,即如果将该节点删除后,剩余各个连通分量的节点权值最大值最小。 如果节点数为偶数,则要求上述节点在剩余节点中,左右两部分节点数目相同;如果节点数为奇数,则要求左部分节点数目比右部分节点数目多一。 示例 1: 输入:edges = [[1,2],[1,3],[1,4],[4,5]], weight = [2,3,1,4] 输出:15 解释:树上的节点权值为 [,2,3,1,4] 。重心是节点 1 ,删除后为两个子树 [2,3,4] 和 [5] 。剩余节点权值分别为 9 和 4,均最小化。 示例 2: 输入:edges = [[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9]], weight = [1,2,3,4,5,6,7,8,9] 输出:31 解释:树上的节点权值为 [,1,2,3,4,5,6,7,8,9] 。重心是节点 5 ,删除后为两个子树 [1,2,3,4,6,7,8,9] 和 [] 。剩余节点权值分别为 33 和 ,均最小化。 提示: 1 <= n <= 10^5 edges.length == n - 1 edges[i].length == 2 1 <= edges[i][], edges[i][1] <= n 1 <= weight.length <= n 1 <= weight[i] <= 10^5 解题思路: 题目要求我们找到树的重心,然后删除重心以上的节点,使得剩余各个连通分量的节点权值最大值最小。 首先,我们需要知道什么是树的重心。树的重心是指树上的一个节点,如果将该节点删除后,剩余各个连通分量的节点数最大值最小,那么这个节点就是树的重心。 我们可以使用两次 DFS 来解决这个问题。第一次 DFS 用来求出树的重心,第二次 DFS 用来计算删除重心以上的节点后,剩余各个连通分量的节点权值之和。 具体来说,我们可以先从任意一个节点开始,进行一次 DFS,求出以该节点为根的子树中的节点数和子树中所有节点的权值之和。然后,我们可以再进行一次 DFS,求出以该节点为根的子树中,删除该节点后,剩余各个连通分量的节点数最大值。我们可以使用一个数组 subsize 来记录每个节点的子树大小,使用一个数组 sum 来记录每个节点的子树中所有节点的权值之和。我们可以使用一个变量 ans 来记录删除重心以上的节点后,剩余各个连通分量的节点权值之和的最小值。 在第一次 DFS 中,我们可以使用一个变量 maxsubsize 来记录以当前节点为根的子树中,最大的子树大小。我们可以使用一个变量 totsize 来记录以当前节点为根的子树中,所有节点的总数。我们可以使用一个变量 cursum 来记录以当前节点为根的子树中,所有节点的权值之和。我们可以使用一个变量 curans 来记录删除当前节点后,剩余各个连通分量的节点数最大值。具体来说,我们可以枚举当前节点的每个子节点,然后递归地计算以该子节点为根的子树中,最大的子树大小。我们可以使用一个变量 cursize 来记录以该子节点为根的子树中,所有节点的总数。我们可以使用一个变量 subsum 来记录以该子节点为根的子树中,所有节点的权值之和。然后,我们可以使用 maxsubsize 来更新以当前节点为根的子树中,最大的子树大小。我们可以使用 totsize 来更新以当前节点为根的子树中,所有节点的总数。我们可以使用 cursum 来更新以当前节点为根的子树中,所有节点的权值之和。最后,我们可以使用一个变量 maxsize 来记录当前节点的父节点到当前节点这条路径上,最大的子树大小。我们可以使用一个变量 parentsize 来记录当前节点的父节点的子树大小。然后,我们可以使用 maxsize 和 totsize - cursize 来计算删除当前节点后,剩余各个连通分量的节点数最大值。最后,我们可以使用 curans 来更新 ans。 在第二次 DFS 中,我们可以使用一个变量 maxsubsize 来记录以当前节点为根的子树中,最大的子树大小。我们可以使用一个变量 totsize 来记录以当前节点为根的子树中,所有节点的总数。我们可以使用一个变量 cursum 来记录以当前节点为根的子树中,所有节点的权值之和。我们可以使用一个变量 parentsize 来记录当前节点的父节点的子树大小。具体来说,我们可以枚举当前节点的每个子节点,然后递归地计算以该子节点为根的子树中,最大的子树大小。我们可以使用一个变量 cursize 来记录以该子节点为根的子树中,所有节点的总数。我们可以使用一个变量 subsum 来记录以该子节点为根的子树中,所有节点的权值之和。然后,我们可以使用 maxsubsize 来更新以当前节点为根的子树中,最大的子树大小。我们可以使用 totsize 来更新以当前节点为根的子树中,所有节点的总数。我们可以使用 cursum 来更新以当前节点为根的子树中,所有节点的权值之和。最后,我们可以使用 parentsize 和 totsize - cursize 来计算删除当前节点后,剩余各个连通分量的节点数最大值。如果当前节点不是树的重心,那么我们可以使用 ans 来更新剩余各个连通分量的节点权值之和的最小值。 最后,我们可以返回 ans。 Java 代码: class Solution { int[] subsize; int[] sum; int ans = Integer.MAX_VALUE; public int getCenter(int[][] edges, int[] weight) { int n = weight.length; subsize = new int[n]; sum = new int[n]; dfs1(, -1, edges, weight); dfs2(, -1, edges, weight); return ans; } private void dfs1(int u, int p, int[][] edges, int[] weight) { subsize[u] = 1; sum[u] = weight[u]; int maxsubsize = ; int totsize = 1; int cursum = weight[u]; int curans = ; for (int v : edges[u]) { if (v == p) { continue; } dfs1(v, u, edges, weight); int cursize = subsize[v]; int subsum = sum[v]; subsize[u] += cursize; sum[u] += subsum; maxsubsize = Math.max(maxsubsize, cursize); totsize += cursize; cursum += subsum; int maxsize = Math.max(cursize, subsize[u] - cursize); int parentsize = totsize - cursize; curans = Math.max(curans, Math.min(maxsize, parentsize)); } int maxsize = Math.max(maxsubsize, totsize - maxsubsize); if (maxsize < ans) { ans = maxsize; } } private void dfs2(int u, int p, int[][] edges, int[] weight) { subsize[u] = 1; sum[u] = weight[u]; int maxsubsize = ; int totsize = 1; int cursum = weight[u]; int parentsize = p == -1 ? : subsize[p]; for (int v : edges[u]) { if (v == p) { continue; } int cursize = subsize[v]; int subsum = sum[v]; subsize[u] += cursize; sum[u] += subsum; maxsubsize = Math.max(maxsubsize, cursize); totsize += cursize; cursum += subsum; int maxsize = Math.max(cursize, subsize[u] - cursize); int childsize = totsize - cursize; int curans = Math.max(Math.min(maxsize, parentsize + childsize), Math.min(subsize[v], totsize - subsize[v])); if (curans < ans) { ans = curans; } dfs2(v, u, edges, weight); } } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cloud、泡泡

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值