第十四届蓝桥杯三月真题刷题训练——第 24 天

第 1 题:旋转

思路:转换行列直接输出

#include<bits/stdc++.h>
using namespace std;
const int N=300;
int f[N][N];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>f[i][j];
        }
    }
//    从列开始 
    for(int i=0;i<m;i++)
    {
        for(int j=n-1;j>=0;j--)
        {
            cout<<f[j][i]<<" ";
        }
        cout<<endl;
    }
 } 
第 2 题:附近最小

思路:滑动窗口,当前范围内的最小值可以依赖前一个范围的最小值来进行更新

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1000010;
ll f[N],n,k;
ll idx=0,min1=0x3f3f3f3f;
void check(ll l,ll r) {
    min1=f[l];
    idx=l;
    for(ll i=l; i<=r; i++) {
        if(f[i]<=min1) { //取最后面的最小值,方便更新
            min1=f[i];
            idx=i;
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin>>n;
    for(int i=1; i<=n; i++) {
        cin>>f[i];
    }
    cin>>k;
    for(int i=1;i<=n;i++)
    {
        ll l=i-k>=1?i-k:1;
        ll r=i+k<=n?i+k:n;
        if(l<=idx)//包含在原先最小值的范围内 
        {
            if(f[r]<=min1)//最新加入进来的是否小于最小值 
            {
                min1=f[r];//更新 
                idx=r;
            }
            cout<<min1<<" ";
        }         
        else{
            check(l,r);//重新更新范围内的最小值 
            cout<<min1<<" ";
        }
    }
}
第 3 题:扫地机器人
思路:贪心,但是卡了第4和第9个样例QAQ
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
ll f[N];//存放机器人位置
ll v[N];//存放对应机器人分配的格子
ll k,n;
bool vis[N];
void solve(int l,int r) {
    ll t=f[r]-f[l]-1;//两个机器人之间的格子数
    ll tt=abs(v[r]-v[l]);//判断相邻两个机器人间谁的格子数多
    if(t>tt) {
        t-=tt;
        v[l]=v[r]=max(v[l],v[r]);//如果足够分配的话,保持两边一致
    } else {
        t-=t;
        v[l]>v[r]?v[r]+=t:v[l]+=t;//如果不够分配的话,使两边的差距尽可能的小
    }
    if(t) {
        v[l]+=t/2;
        v[r]+=t/2;
        if(t%2) {
            v[r]++;
        }
    }
}
int main() {
    cin>>n>>k;
    ll len;
    for(int i=0; i<k; i++) cin>>f[i];
    sort(f,f+k);
    if(k==1)cout<<2*(n-1)<<endl;
    else {
        //初始化起始端和末端
        f[0]-1>=0?v[0]=f[0]-1:v[0]=0;
        v[k-1]=n-f[k-1];
        for(int i=0;i<k-1;i++) {
            solve(i,i+1);
        }
        sort(v,v+k);
        cout<<v[k-1]*2<<endl;
    }
}
/*
解题思路:
本题为一道比较明显的二分题目。

题目要求最少花费时间。由于每个机器人的工作时间可能不同,那么这些机器人各自的花费时间中的最大值(设为 t )的就是本题要求的答案,
需要做的是使得 t 最小。将最大花费时间(t)最小化,显然需要使用二分求解。

假设某个机器人需要清扫 a,b,c,d 四个格子,因为这个机器人清扫完还需要回到最初始的位置,所以无论这个机器人初始位置在什么地方,
其清扫路径的本质都是重复两次 a 到 b,b 到 c,c 到 d 的过程,花费时间为 6,由此,假设某个机器人清扫的格子范围为 l,
那么这个机器人花费的时间为 (l-1)\times*2。所以只需要对机器人清扫的范围(l)进行二分即可,最后的答案为 t=(l-1)\times*2。

显然当每个机器人清扫的范围大小相同时,花费时间最小。
可以对清扫范围进行二分,然后验证其答案的正确性即可,判断条件是清扫范围可以使得每个格子都能够扫到

可以明显的知道,最左边的格子由左边第一台机器人清扫,花费时间是最少的,在此可以采用贪心的思想,
让每台机器人都要优先清扫其左边还未扫的到格子,然后再往右扫,在二分得到的范围下往右扫得越多越好,
这样可以减少右边下一个机器人需要往左扫的范围,增加其往右扫的范围,以此类推,可减少清扫时间。

综上,本题采用二分加贪心的思想解答。
*/
#include<bits/stdc++.h>
using namespace std;

int robot[1000005];//机器人位置
int n, k;

bool check(int len)
{
    int sweep = 0;//sweep代表清扫到了哪个位置
    for(int i = 1; i <= k; i++)
    {
        if(robot[i] - len <= sweep)//如果当前机器人只扫左侧,能够覆盖左侧未清扫的位置,则可进行当前机器人的清扫
        {
            if(robot[i] <= sweep)//如果当前机器人已经处于清扫过的位置,则当前机器人只扫右侧区域
                sweep = robot[i] + len - 1;
            else//否则从上一个清扫到的位置继续
                sweep += len;
        }
        else//当前机器人只扫左侧,不能覆盖左侧未清扫的位置,当前方案不可行,返回
            return 0;
        //cout<<sweep<<endl;
    }
    return sweep>=n; //表示当前方案可行
}

int main()
{
    cin >> n >> k;
    for(int i = 1; i <= k; i++)
    {
        cin >> robot[i];
    }
    sort(robot + 1, robot + k + 1);//首先对机器人的位置进行排序
    int L=0, R=n, M, ans;
    while(L <= R)//二分清扫范围
    {
        M = (L + R) / 2;
        if(check(M))//如果当前方案可行,则缩小清扫范围,试图寻找更小的方案
        {
            R = M - 1;
            ans = M;
        }
        else//如果方案不可行,则扩大清扫范围,寻找可行方案
            L = M + 1;
    }
    cout << (ans - 1) * 2 << endl;//计算并输出答案
    return 0;
}
第 4 题:窗口

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值