2019年大题

2019年省A第一场

F、完全二叉树的权值

给定一棵包含 N 个节点的完全二叉树,树上每个节点都有一个权值,按从上到下、从左到右的顺序依次是 A1, A2, · · · AN,如下图所示:
现在小明要把相同深度的节点的权值加在一起,他想知道哪个深度的节点权值之和最大?如果有多个深度的权值和同为最大,请你输出其中最小的深度。注:根的深度是 1。
【样例输入】
7
1 6 5 4 3 2 1
【样例输出】
2
思路: 边输入边累加,当到达下一层时比较权值和,更新maxi depth为最大权值和和对应最小深度。
代码:

typedef long long ll;
int main(){
    ll n,in,mi=1,num=1,maxi=0,t=0,depth=0,cnt=1;
    cin>>n;
    for (ll i=0;i<n;i++){
        cin>>in;
        if (i<num) t+=in;
        else{
            //找最大权值和
            if (maxi<t){
                maxi=t;
                depth=cnt;
            }
            t=in; //重新计算最大权值和
            mi*=2; num+=mi; //节点个数分裂
            cnt+=1;
        }
    }
    //最深层别忘记判断
    if (maxi<t){
        maxi=t;
        depth=cnt;
    }
    cout<<depth;
    return 0;
}

G:外卖店优先级

“饱了么”外卖系统中维护着 N 家外卖店,编号 1 ∼ N。每家外卖店都有一个优先级,初始时 (0 时刻) 为 0。每经过 1 个时间单位,若外卖店没有订单则优先级会减 1,最低减到0;若有订单则每有一单优先级加 2。
若某时刻优先级大于5,店铺被系统加入优先缓存中;若优先级小于等于3,则被清除出优先缓存。
给定 T 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优先缓存中。
【样例输入】
2 6 6
1 1
5 2
3 1
6 2
2 1
6 2
【样例输出】
1
思路: 将订单信息按照先时间后店铺升序的方式排序,初始化1个优先级序列res[]和1个是否在缓冲队列join[],每个时刻维护1个map来存放该店铺有几个订单,并实时更新优先级序列和缓冲队列。
代码:

#include <algorithm>
#include <cmath>
#include <map>
#define maxn 100001
struct node{int time,num;};
node in[maxn]; //输入
int res[maxn],join[maxn];//存储优先级和缓冲队列
//订单排序
bool cmp(node a,node b){
    if (a.time==b.time) return (a.num<b.num);
    return (a.time<b.time);
}
int main(){
    int n,m,t,j=1,k=0,cnt=0;
    cin>>n>>m>>t;
    //矩阵初始化
    for (int i=0;i<m;i++) cin>>in[i].time>>in[i].num;
    for (int i=1;i<=n;i++){
        res[i]=0;  //存储值
        join[i]=0; //非优先队列
    }
    //按时间先后、num大小排序
    sort(in,in+m,cmp);
    map<int,int> have; //存储每个单位有外卖的店家
    while (k<m && j<=t){
        while(in[k].time==j){
            if (have.find(in[k].num)==have.end()) have[in[k].num]=1; //有1单
            else have[in[k].num]+=1; //不只有1单
            k+=1;
        }
        for (int i=1;i<=n;i++){
            if (have.find(i)==have.end()){
                res[i]=max(res[i]-1,0);//最少是0
                if (join[i] && res[i]<4){
                    join[i]=0; //清出队列
                    cnt-=1;
                }
            }
            else{
                res[i]+=2*have[i];
                if (!join[i] && res[i]>5){
                    join[i]=1; //加入队列
                    cnt+=1;
                }
            }
        }
        have.clear();
        j+=1; //下个时刻
    }
    cout<<cnt;
    return 0;
}

H、修改数组

长度为 N 的数组 A = [A1, A2, · · · AN],有可能有重复出现的整数。现在小明要按以下方法将其修改为没有重复整数的数组:
当修改Ai时,检查Ai是否在A1∼Ai−1中出现过。若出现过则给 Ai 加1;若新的Ai仍在之前出现过,持续给Ai加1。给定初始的 A 数组,请你计算出最终的A数组。
【样例输入】
5
2 1 1 3 4
【样例输出】
2 1 3 4 5
思路: 暴力循环为O(n^2/2)复杂度,没时间的话捞分用
巧妙地利用并查集:初始化i的父亲为i,依次遍历输入的数组,使a[i] = getf(a[i]),再令f(a[i]) = f(a[i]+1)即可。
并查集思路copy自CSDN大佬
改写代码如下:

#define maxn 1000001
int f[maxn],in[maxn];
//并集找根
int father(int x){
    if (f[x]==x) return x;
    return f[x]=father(f[x]);
}
int main(){
    int n; cin>>n;
    for (int i=1;i<=n;i++) f[i]=i;//初始化根节点
    for (int i=1;i<=n;i++){
        cin>>in[i];
        in[i] = father(in[i]);
        f[in[i]] = father(in[i]+1); //该数字已用,将根+1
        cout<<in[i]<<" ";
    }
    return 0;
}

I 糖果

糖果店的老板一共有 M 种口味的糖果出售,编号 1 ∼ M,老板将糖果K 颗一包整包出售。小明希望能品尝到所有口味的糖果,给定 N 包糖果,计算小明最少买几包,就可以品尝到所有口味的糖果。
【样例输入】
6 5 3 (N M K)
1 1 2
1 2 3
1 1 3
2 3 5
5 4 2
5 1 2
【样例输出】
2

J、组合数问题

在这里插入图片描述
【输入格式】
第一行两个数 t, k,其中 t 代表该测试点包含 t 组询问,k 的意思与上文中相同。接下来 t 行每行两个整数 n, m,表示一组询问。
【输出格式】
输出 t 行,每行一个整数表示对应的答案。由于答案可能很大,请输出答案除以 109 + 7 的余数。
【样例输入】
1 2
3 3
【样例输出】
1
【样例说明】
在所有可能的情况中,只有 C1 2 = 2 是 2 的倍数。
【样例输入】
2 5
4 5
6 7
【样例输出】
0
7
【样例输入】
3 23
23333333 23333333
233333333 233333333
2333333333 2333333333
【样例输出】
851883128
959557926
680723120

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值