2024牛客暑期训练营第三场A,B,L赛时报告

赛时解决题目:A,B,L


        

L:

题意:

        说给个9*9数独的数独表,然后让你改其中任意个数字变成'*'作为雷,不能全改,然后输出。

解题思路:

        观察一下会发现,数字8最特殊,中间的格子旁边一定有八个格子,那么对于数独来说,肯定有数字8在数独表非边缘位置,那么只需要找到这个坐标即可。

///秋雨
char a[20][20];
void cout_ans()
{
    for(int i=1;i<=9;i++)
    {
        for(int j=1;j<=9;j++)
        {
            cout<<a[i][j];
        }cout<<'\n';
    }
}
void solve()
{
    bool ret=0;
    ll x,y;
    for(int i=1;i<=9;i++)
    {
        for(int j=1;j<=9;j++)
        {
            cin>>a[i][j];
            if(a[i][j]=='9')a[i][j]='*';
            if(a[i][j]=='8'&&i!=1&&i!=9&&j!=1&&j!=9)
            {
                ret=1;
                x=i,y=j;
            }
        }
    }
    if(ret)
    {
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<=9;j++)
            {
                a[i][j]='*';
            }
        }
        a[x][y]='8';
    }
    cout_ans();
}

B:

题意:

        说给你n个数,你有一辆车距离某面墙d,问每次用这些数之一逼近,如果选取的数字大于d,那么距离变成h-d,h是对应的数字。问距离墙面最小距离是多少。

解题思路:

        其实跟组合差不多,你会发现,这n的数字的gcd就是它每次能前进的最小步长,而因为它是gcd,所以又可以代替这些数字的作用,那么答案便很显然了,要么是d%gcd求出来的东西,要么是撞一下墙后得到的数值,我这里gcd出来的值用x代替,也就是x-d%x。两者取最小值即可。赛时我是后面稍微模拟了一下,不过完全没有必要。

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define int long long
#define double long double
#define Int __int128
#define pb push_back
#define N (int)1e5+10
#define MAX_LOG 21
#define ff first
#define ss second
#define M 5005
#define ull unsigned long long
using namespace std;
const double PI=3.1415926535897932385;
const ll LLMAX=9223372036854775807ll;
const ll LLMIN=-9223372036854775808ll;
//const int MAX_INT=0x3f3f3f3f;
const int IIMAX=2147483647;
const int IIMIN=-2147483648;
const int INF=0x3f3f3f3f;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b)
{
    if(b) while((a%=b)&&(b%=a));
    return a+b;
}//最大公约数函数
ll spid(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;
}//快速幂函数
///泡沫在阳光下闪烁,像星辰在寂静得夜空中闪耀

///秋雨
ll a[N];
void solve()
{
    ll n,d;cin>>n>>d;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=2;i<=n;i++)
    {
        a[i]=gcd(a[i],a[i-1]);
    }
    d%=a[n];
    ll ans=d;
    unordered_set<ll>st;
    while(!st.count(d))
    {
        st.insert(d);
        d-=a[n];
        d=abs(d);
        ans=min(ans,d);
    }
    cout<<ans<<'\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t=1;
//    cin>>t;
    while(t--)
    {
        solve();
    }
}
///在秋天邂逅, 在春天发芽,在夏天壮大,在秋天萧瑟,在冬天萎缩,

///而后,春天再度归来。




A:(组合)

题意:

        这题对于我来说,难,但想出来好像又很简单。

        题意是:有n个人,每个人都有自己对应的体力 h[i],然后在河的一岸,有艘破船,这些人想过岸,但是每次坐船的时候都会消耗1点体力(不管是过去或回来),并且这艘船,至少得有L个人才能开动,最多能载R个人,问能不能全部过去。

解题思路:

        一开始,我往模拟上面想,想的老对老对了,然后一交,欸嘿,wa了,wa了三发后老实了,开始想别的,然后就想到了船夫的问题(还是船夫的问题)。

        我们可以贪心的知道,我们肯定希望,运过去的人越多越好,也就是最好满满当当坐R个人然后塞R-L个人过去,所以我们可以知道我们最大的渡河次数(只过去,不算回来的)是yun=(n-r+(r-l-1))/(r-l);这应该很容易理解。

        然后因为每一次运都需要船夫,所以每一次运我们需要找到l个壮丁来当船夫(就因为这个一开始干模拟去了,过不去老不开心了),那么我们就给这n个人按照体力值排个序,我们处理一下h[i],让h[i]=h[i]-1>>1;为什么呢,h[i]-1说明它可以把自己运过去,h[i]-1>>1说明它可以承担船夫做一次来回的次数。

        我们设一个变量ans作为需要船夫的个数。一开始为0。

        那么我们从大到小遍历,对于前L个人,如果体力值超过了yun,也就是说,每一次船往来他都能干苦力,那么便不用对ans做处理,但也不能加上h[i],因为一个人只能在一次往返中担任一个船夫的任务,如果小于yun,那么这个船夫只能填上h[i]次的往返,所以ans需要+h[i]-yun,也就是说,我们需要补上yun-h[i]个船夫空位的意思。

        对于后续的人,如果还存在大于yun的体力的人,那肯定意味着,我们必然拥有L个人能跑完所有yun次往返,如果不存在,那么我们可以给他分配它他当船夫的位置,因为遍历到这,又不符合大于yun,所以这个船夫肯定最多担任小于yun次的 往返,不用考虑说他一个人干两个人活的问题。所以这里直接加上h[i]即可。

        那么最后再判断一下,ans是否大于等于0(是否可用船夫数量大于需要的数量),输出yes/no即可。

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define int long long
#define double long double
#define Int __int128
#define pb push_back
#define N (int)5e5+10
#define MAX_LOG 21
#define ff first
#define ss second
#define M 5005
#define ull unsigned long long
using namespace std;
const double PI=3.1415926535897932385;
const ll LLMAX=9223372036854775807ll;
const ll LLMIN=-9223372036854775808ll;
//const int MAX_INT=0x3f3f3f3f;
const int IIMAX=2147483647;
const int IIMIN=-2147483648;
const int INF=0x3f3f3f3f;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b)
{
    if(b) while((a%=b)&&(b%=a));
    return a+b;
}//最大公约数函数
ll spid(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;
}//快速幂函数
///泡沫在阳光下闪烁,像星辰在寂静得夜空中闪耀

///秋雨
ll h[N];
void solve()
{
    ll n,l,r;
    cin>>n>>l>>r;
//    priority_queue<ll,vector<ll>,greater<ll>>q;
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        cin>>h[i];h[i]=(h[i]-1)>>1;///运的次数
    }
    ll yun=(n-r+(r-l-1))/(r-l);
    sort(h+1,h+1+n);
    reverse(h+1,h+1+n);
    for(int i=1;i<=n;i++)
    {
        if(i<=l&&h[i]<=yun)ans-=yun-h[i];
        else if(i>l)ans+=h[i];
    }
//    cout<<ans<<'\n';
    if(ans>=0) cout<<"Yes\n";
    else cout<<"No\n";
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t=1;
//    cin>>t;
    while(t--)
    {
        solve();
    }
}
///在秋天邂逅, 在春天发芽,在夏天壮大,在秋天萧瑟,在冬天萎缩,

///而后,春天再度归来。



  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值