牛客小白月赛 66 (A~F)

        为了应付开学考试摸了两星期,这场小白月赛感觉比较简单,正好适合复建。

A.先交换

题目链接

题意

        给一个数组a,每次操作可以交换满足 i < j 且 a[i] > a[j] 的两个数,问经过多少次操作使得a[1] 为奇数。

 思路

        水题,如果开头不是奇数,往后遍历找一个奇数小于a[1]的,找不到就是-1,找到就是1。开头是奇数直接是0。

Code

#include<bits/stdc++.h>

using namespace std;

void solve()
{
    int n;
    cin >> n;
    vector<int>a(n + 1);
    for(int i = 1;i <= n;i ++)
        cin >> a[i];
    if(a[1] & 1) cout << 0 << endl;
    else
    {
        for(int i = 2;i <= n;i ++)
            if(a[i] % 2 == 1 && a[i] < a[1])
            {
                cout << 1 << endl;
                return ;
            }
        cout << "-1" << endl;
        return ;
    }
}
int main()
{
    int tt;
    cin >> tt;
    while(tt --)
        solve();
    
}

 B.再交换

题目链接

题意

        给两个长度为n的十进制数a,b,可以选择i、j,交换ai和bj,ai是从左到右第i个数位,bj同理。问交换一次能否使a<b?

思路

         对于两个数,高位第一个不一样的数位就决定了两个数的大小(129****一定大于120****),遍历寻找第一个不一样的数位i,如果有ai > bi,就把该位交换,如果ai < bi,说明已经满足条件a < b,就交换前面任意一位相同的,注意i == 0的特判

Code

#include<bits/stdc++.h>

using namespace std;

void solve()
{
    int n;
    string A,B;
    cin >> n >> A >> B;
    for(int i = 0;i < A.size();i ++)
    {
        if(A[i] == B[i]) continue;
        if(A[i] > B[i])
        {
            cout << i + 1 << " " << i + 1 << endl;
            return ;
        }
        else if(A[i] < B[i])
        {
            if(i >= 1) cout << i << " " << i << endl;
            else cout << i + 2 << " " << i + 2 << endl;
            return ;
        }
    }
}
int main()
{
    int tt;
    cin >> tt;
    while(tt --)
        solve();
}

 C.空洞骑士

题目链接

题意

     给一个[0,1e9]的数轴,数轴上有m个吉欧,小骑士会从起点s出发,收集所有吉欧后到达终点t,要求给出一个s和t,使得小骑士采取最优策略的情况下行进距离最长

思路

         考虑了两种情况,首先是起点和终点相邻在数轴最边界,这样距离大概是2 * [距起点和终点最远的吉欧的距离]。

        第二种是起点在吉欧中间,想着小骑士可以多往返几次,但实际上由于小骑士会采取最优策略,他肯定会先走到离终点最远的吉欧的位置再顺路直接到终点,这样的距离大概是[距起点最远的吉欧距离 + 距终点最远吉欧的距离],显然不如第一种

        继续考虑第一种情况,显然发现起点和终点可以取[0,1e9],[0,1],[1e9,1e9 - 1]三种情况,分类讨论一下即可(注意可能多个吉欧位于同一个点)

Code

#include<bits/stdc++.h>

using namespace std;

void solve()
{
    int m,flag = 0;
    cin >> m;
    vector<int>a(m + 1);
    for(int i = 1;i <= m;i ++) 
    {
        cin >> a[i];
        if(i > 1 && a[i] != a[i - 1])
            flag = 1;
    }
    if(!flag)
    {
        //cout << "?" << endl;
        cout << 0 << " " << (int)1e9 << endl;
        return ;
    }
    int MIN = 1e9 + 7,MAX = 0;
    for(int i = 1;i <= m;i ++)
    {
        MIN = min(MIN,a[i]);
        MAX = max(MAX,a[i]);
    }
    int info1 = (int)2e9 - 1 - 2 * MIN;
    int info2 = 2 * MAX - 1;
    if(info1 >= info2) cout << (int)1e9 << " " << (int)1e9 - 1 << endl;
    else cout << 0 << " " << 1 << endl;
}
int main()
{
//     int tt;
//     cin >> tt;
//     while(tt --)
        solve();
}

 D.障碍

题目链接

题意

        在[0,n]的数轴内有m个障碍,现在可以从中移除多个障碍,称移除的障碍个数为x,称区间[0,n]内最长段长度为L,要求最大化L - x^{2}

思路

        首先考虑L - x^{2},如果x^{2}大于L,答案一定不会更优,所以x的最大值实际上只有\sqrt{L},接下来考虑暴力枚举。

         没想到怎么枚举,看题解学到一个O(n^2)的枚举,第一层枚举第i个障碍,第二层枚举移除了前j个障碍,答案即为a[i] - a[i - j + 1] - j * j,维护一个最大值即可。

        注意处理边界问题,可以插入一个a[0] = 0和a[m + 1] = m,直接进行枚举就可以防止边界问题出错。

Code

#include<bits/stdc++.h>

using namespace std;

void solve()
{
    int n,m;
    cin >> n >> m;
    vector<int>pos(m + 2);
    for(int i = 1;i <= m;i ++) cin >> pos[i];
    pos[0] = 0,pos[m + 1] = n;
    int res = 0;
    for(int i = 1;i <= m + 1;i ++)
    {
        for(int j = 0;j <= min(i - 1,(int)sqrt(n));j ++)
        {
            res = max(res,pos[i] - pos[i - j - 1] - j * j);
        }
    }
    cout << res << endl;
}
int main()
{
//     int tt;
//     cin >> tt;
//     while(tt --)
        solve();
}

 E.生成树与路径

题目链接

题意

        给定n,m,构造一个无向带权简单联通图,满足该图的最小生成树边权和等于1~n的最短路长度,同时要求边权为[1,m]的序列。

思路

        首先考虑 最小生成树,不难想到最小生成树的边权和为n * (n - 1) / 2,也就是连一条线,边权分别为(1,2,....,n - 1),要想最短路也是这个值,就需要对于1 - 3,2 - 4,3 -5等等边的边权,都小于等于链1-3,2-4等等的边权和。

       然后写一写就会发现,就可以发现我们按照两点相差从小到大的顺序分配边权,就可以实现上述效果。

        e.g. n = 4,m = 6

        w{1,2} = 1,w{2,3} = 2,w{3,4} = 3;

        w{1,3} = 4,w{2,4} = 5;

        w{1,4} = 6 

Code

#include<bits/stdc++.h>

using namespace std;

void solve()
{
    int n,m;
    cin >> n >> m;
    int cnt = 1;
    for(int dif = 1;dif <= n - 1;dif ++)
    {
        for(int j = 1;j + dif <= n;j ++)
        {
            cout << j << " " << j + dif << " " << cnt ++ << endl;
            if(cnt > m) break;
        }
        if(cnt > m) break;
    }
}

int main()
{
    int tt;
    cin >> tt;
    while(tt --)
        solve();
}

 F.球球大作战

题目链接

题意太长懒得写了

思路

        1.首先可以想到,对于ai > aj,如果aj能找到一个合法顺序,那么ai肯定也能找到一个合法顺序。先排序,然后可以二分去找最小的能找到合法顺序的球球。

        2.可以注意到每次碰撞后小球一定不会变大,那么当check(ai)时,我们让除了ai的所有球球全都互相碰撞,最后得到的一定是一个最小的球球,如果ai比最小的球球还小,那么就无法找到合法顺序

Code

#include<bits/stdc++.h>

using namespace std;
const int maxn = 1e5 + 10;
int n;
pair<int,int> a[maxn];
bool check(int id)
{
    int temp = (id == n) ? a[n - 1].first : a[n].first;
    for(int i = n;i >= 1;i --)
    {
        if(i == id) continue;
        temp = (temp + a[i].first) / 2;
    }
    if(a[id].first >= temp) return true;
    else return false;
}
int main()
{
    cin >> n;
    for(int i = 1;i <= n;i ++) cin >> a[i].first,a[i].second = i;
    vector<int>vis(n + 1);
    sort(a + 1,a + 1 + n);
    int l = 1,r = n;
    while(l < r)
    {
        int mid = (l + r) >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    for(int i = l;i <= n;i ++)
        vis[a[i].second] = 1;
    for(int i = 1;i <= n;i ++)
        if(vis[i]) cout << "1";
        else cout << "0";
    cout << endl;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值