天梯赛题解

本文是关于算法竞赛中涉及图论和深度优先搜索的题解合集,包括最优乘车、小H系列游戏等。通过二分、最短路、动态规划等方法解决问题,提供解题思路和代码实现。
摘要由CSDN通过智能技术生成

A 大佬的生日大礼包

https://ac.nowcoder.com/acm/contest/53548/A

思路:

根据题意 发现答案呈单调性 即最多可以发放k份物品 则一定可以发放(0,k)件物品,则可以使用二分 来归并到 答案。那么我们只需要一个 check(p) 函数判断 答案p 是否可行即可。发现 三个礼包都减去一个u盘和一个鼠标,则 豪华礼包剩一个键盘,幸运礼包剩一个 鼠标,普通礼包剩一个u盘,满足 区分性。因为 希望相邻的参赛选手拿到的礼包类型都不同,则易证明 每种礼包类型不能超过 P/2。每种礼包最多能为答案贡献为 min(该礼包个数,P/2);

代码

bool check(ll a,ll b,ll c,ll k){
     a=a-k;b=b-k;
    if(a<0||b<0)return false;
    ll cnt=0;
    ll kk=(k+1)/2;
    cnt=cnt+min(a,kk);
    cnt+=min(b,kk);
    cnt+=min(c,kk);
    if(cnt>=k)return true;
    else return false;
}

B 圣诞节糖果

https://ac.nowcoder.com/acm/contest/53548/B

思路:

根据题意 我们只需要选择两堆糖果,然后 可以获得两堆糖果总数对p取模的余数的个数。暴力做法 就是两个for 循环即可,但 因为 n的数据范围是(2,1e5) 所以会超时,但是我们可以发现我们将n堆糖果对p取余 之后排序,就可以 发现 当遍历到第i堆糖果的时候,因为 都需要对p取余,所以我们可以发现,当两堆糖果 个数总和大于P的时候 一定是小于等于a[i]的,所以我们对我们贡献最大的就是两堆之和小于等于P的,并且需要满足尽可能大,满足单调性,即存在 一个a[j])为答案时,必然是存在所有a[k]+a[i]<=P k属于(i+1,j-1)都是小于等于P的,且必然存在 所以a[s]+a[i]>P s属于(j+1,n)。

代码

    for(int i=1;i<=n;i++){
        ll l=i+1,r=n;
        while(l<r){
            ll mid=(l+r+1)>>1;
            if(a[i]+a[mid]<p)l=mid;
            else r=mid-1;
        }
        if(i<r)maxx=max(maxx,(a[i]+a[r])%p);
    }

C 最优乘车

https://ac.nowcoder.com/acm/contest/53548/C

思路:

就是一个简单的最短路问题,难点在与 建图方式,因为我们需要求从饭店到S公园的过程中换车的次数最少,类似求闭包,我们可以将所有公交路线上的车能互相到达的车站都连一条边,等同于 保证在同一条公交路线最多只走一次,所以 最终的最短路距离减-1 就是换乘次数。

int main(){
  int m,n;cin>>m>>n;
    vector<vector<int>>v(n+10);
    string s;getline(cin,s);
    for(int i=0;i<m;i++){
        getline(cin,s);int sum=0;
        for(int j=0;j<s.size();j++){
            if(s[j]==' ') v[i].push_back(sum),sum=0;
            else sum=sum*10+s[j]-'0';
        }
        v[i].push_back(sum);
    }
    for(int i=0;i<m;i++){
        for(int j=0;j<v[i].size();j++){
            for(int k=j+1;k<v[i].size();k++){
               f[v[i][j]][v[i][k]]=1; 
        }
     }
    }
     memset(dist,0x3f,sizeof(dist));
    queue<int>q;q.push(1);dist[1]=0;
     while(q.size()){
         int k=q.front();q.pop();
         for(int i=1;i<=n;i++){
             if(f[k][i]&&dist[i]>dist[k]+1){
                 dist[i]=dist[k]+1;q.push(i);
             }
         }
     }
        if(dist[n]==0x3f3f3f3f)cout<<"NO"<<endl;
        else cout<<max(dist[n]-1,0)<<endl;
    return 0;
}

D 小H和游戏

https://ac.nowcoder.com/acm/contest/53548/D

思路:

阅读题意 发现每次轰炸都会波及到与该城市距离不超过2的城市。 可以对每个点 维护三个信息,该点被轰炸的次数,该点儿子被轰炸的次数,该点孙子被轰炸的次数。然后 就可以类比到 题目要求 每次 该城市被轰炸,会影响到的点为,该点的儿子 该点的孙子,该点的父亲,该点父亲的儿子,该点父亲的父亲。 记录答案为 该点被轰炸的次数+该点父亲的儿子被轰炸的次数+该点父亲的父亲的孙子被轰炸的次数。 所以我们只需要预处理一下找到每个人 的父亲是谁就行,做一遍dfs 即可。

代码

void dfs(ll u,ll fa){
    f[u]=fa;
    for(int i=h[u];i!=-1;i=ne[i]){
        ll j=e[i];
 
  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值