牛客(浙江机电职业技术学院第八届新生亮相赛(同步赛))

本文详细解析了编程竞赛中的四个题目,涵盖最短路径、交换次数优化、数列排序以及字符串处理,展示了实际问题如何转化为算法解决方案。
摘要由CSDN通过智能技术生成

由于本人现在还比较菜,只写了其中的一些稍为简单的比赛在这里

题目A:吝啬的拒绝  大意---有n个奶牛,p个牧场,牧场间的有c个道路,问让你选一个牧场放吃的,所有的奶牛都去这个牧场吃,问你所有奶牛走的最小距离

做法:(在比赛时没做出来,同学都做出来了,55好好反省)拿到题一看是一道最短路问题,而且是无向边,建两条边就好了,再枚举农场取最小 

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1000,M=510,INF=1e9;
int n,p,c;
int d[N][N];
int ext[M];
void floyd()
{
    for(int k=1;k<=p;k++)
        for(int i=1;i<=p;i++)
            for(int j=1;j<=p;j++)
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
int main()
{
    cin>>n>>p>>c;
    for(int i=1;i<=p;i++)//初始化
    for(int j=1;j<=p;j++)
        if(i==j)d[i][j]=0;
            else d[i][j]=INF;
    
    for(int i=1;i<=n;i++)cin>>ext[i];//全部的牛牛在的农场
    
    while(c--)//距离,是双向边
    {
          int a,b,w;
          cin>>a>>b>>w;
          d[a][b]=d[b][a]=min(d[a][b],w);
    }
    floyd();
    int ans=0x3f3f3f3f;
    for(int i=1;i<=p;i++)//所有的牧场
    {
        int tmp=0;
        for(int j=1;j<=n;j++)tmp+=d[i][ext[j]];//每个牛牛到当前枚举的牧场的距离
        ans=min(ans,tmp);//取最小
    }
    cout<<ans<<endl;
    return 0;
}

题目C:数列排序          给定一个数列a,数都不相同,现在要求把这个数列从小到大排序,每次允许交换其中任意一对数,问最小的交换次数

做法:这是一道非常常见的交换次数的题,洛谷 也有,我们可以用map,map是记录原本数的下标,再用另一个复制数组排序,跟原数组一一比对,相同则下一个,不相同操作次数++,思想是直接把需要回归原位的数的现在位置直接换成它原位上的数就行,也要把下标改了。

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
const int N = 1e5+10;
map<int,int>mp;//记录下标
long long a[N],b[N];
int main()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        b[i]=a[i];
        mp[a[i]]=i;
    }
    sort(b+1,b+1+n);
    long long ans=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==b[i])continue;
        ans++;
        int t=mp[b[i]];
        mp[a[i]]=t;
        a[t]=a[i];
    }
    cout<<ans<<endl;
    return 0;
}

题目E: 自由还是爱情 这是个问题   --->让你选择价值大的那个,直接暴搜,就不多説了

#include<iostream>
#include<cstring>
using namespace std;
const int N = 40;
struct Node{
    int sp,val;
}a[N],b[N];
int  ans1,ans2;
int al,bl;
bool st[N];
void dfs(int u,int val,int sum)
{
    ans1=max(ans1,val);
    if(u>=al||sum<=0)return;
    for(int i=u;i<al;i++)
    {
        if(!st[i]&&a[i].sp<=sum)
        {
            st[i]=true;
            dfs(i+1,val+a[i].val,sum-a[i].sp);
            st[i]=false;
        }
    }
}
int main()
{
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        if(x==0)
        {
            a[al].sp=y;
            a[al].val=z;
            al++;
        }
        else
        {
            b[bl].sp=y;
            b[bl].val=z;
            bl++;
        }
    }
    dfs(0,0,k);
    memset(st,false,sizeof st);
    dfs1(0,0,k);
    if(ans1>=ans2)
        cout<<ans1<<' '<<0<<endl;
    else 
        cout<<ans2<<' '<<1<<endl;
}

 题目G:农场-------->夜雷在新日暮里买了一块地来经营史莱姆农场,因为经费紧张,他的钱只够买一只史莱姆但是不用担心,史莱姆的繁殖能力非常强,每一天结束它都会分裂成a个史莱姆,分裂的史莱姆还会再分裂同时夜雷的每个畜栏都有p的容量,当畜栏满了,他就会把该畜栏的史莱姆卖掉夜雷想让你帮他算算,b天后他会拥有多少只史莱姆

做法:这一题还不太想得懂,为什么要用快速幂,会的可以教教我55,以后要敏感点了看见取模之类的就要想到快速幂了 

#include<iostream>
using namespace std;
typedef long long LL;
int qmi(LL a,LL b,LL p)
{
    LL ans=1;
    while(b)
    {
        if(b&1)ans=ans*a%p;
        b>>=1;
        a=a*a%p;
    }
    return ans;
}
int main()
{
    int T;cin>>T;
    while(T--)
    {
        LL a,b,p;
        cin>>a>>b>>p;
        cout<<qmi(a,b,p)<<endl;
    }
    return 0;
}

题目 j:兔子不会种树---------->阿兔有那么一个k叉树,每秒生长一层假设k为3 则1连接2,3,4 2连接5,6,7 3连接8,9,10 4连接11,12,13 5连接14,15,16n个询问,问x数在第几秒能生长出来

做法:特判一个k是1的情况直接输出x-1的情况就好了,其它就直接求,每次找的是每一层最大的那一个数,大于等于x就停下来就好了,注意x要开LL 

#include<iostream>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int k;cin>>k;
    int q;cin>>q;
    while(q--)
    {
        long long x;cin>>x;
        if(k==1)cout<<x-1<<endl;
        else
        {
            long long s=1,now=1;
            int t=0;
            while(s<x)
            {
                t++;
                now*=k;
                s+=now;
            }
            cout<<t<<endl;
        }
    }
    return 0;
}

题目K:淘金币  ------> 文文将得到一个由”A”和”B”组成的字符串s。涛涛告诉文文可以执行以下两种操作:(1) 选择一个子串AB,将其更改为BC,然后得到一块钱。(2) 选择一个子串BA,将其更改为CB,然后得到一块钱。问文文最多能得到多少钱?

做法:我们可以先观察一些变换的发生,发生1变换是把A变没在B后加一个C,但是C又没用,B是一直存在的,但是后面有了C这个B就不能进行任何变换,但是我们可以发现这个B还可以去跟前面的A变换再生成BC。变换2则是与它相反。 我们可以想到1.当开头或结尾存在至少一个B就一定可以把所有的A都合并完,得到的金币数也就是A的个数,当有两个B连在一块时也可以把所有的A都合并完,一个向前一个向后。当这两种情况都不存在时,就是这种AABABAA这些B把A分成了B的个数+1个区间,我们的B只有向一个方向合并,所以我们只能舍去一个区间,要想合并次数最多,我们只能舍去一个最小A的区间,所以这种情况直接去找A个数最少的一段,用总的A的个数减去这一段就行了

#include<iostream>
using namespace std;
const int N = 1e6;
int main()
{
    int T;cin>>T;
    string s;
    while(T--)
    {
        cin>>s;
        int slen=s.size()-1;
        int a=0,b=0;
        bool is_exist=false;
        if(s[0]=='B'||s[slen]=='B')is_exist=true;
        for(int i=0;i<slen;i++)
        {
            if(s[i]=='A')a++;
            if(s[i]==s[i+1]=='B')is_exist=true;
        }
        if(s[slen]=='A')a++;
        if(is_exist)
        {
            printf("%d\n",a);
            continue;
        }
        int ans=0x3f3f3f3f;
        int cnt=0;
        for(int i=0;i<=slen;i++)
        {
            if(s[i]=='A')cnt++;
            else 
            {
                ans=min(ans,cnt);
                cnt=0;
            }
        }
        ans=min(ans,cnt);
        printf("%d\n",max(0,a-ans));
    }
    return 0;
}

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值