牛客小白月赛73(A~E)

A.最小的数字

思路:

枚举n,n+1,n+2,即可找到符合条件且较小的值

代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 100010,mod = 1e6+7;
typedef long long ll;
typedef pair<int,int> pii;

int n,m,k;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    cin >> n;
    while(1) 
    {
        if(n % 3 == 0) 
        {
            cout << n << '\n';
            break;
        }
        n++;
    }
    return 0;
}

B.优美的GCD

思路:

构造的一种直接的方法x = n, y = 2 * n。

代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 100010,mod = 1e6+7;
typedef long long ll;
typedef pair<int,int> pii;

int n,m,k;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int tt;
    cin >> tt;
    while(tt--)
    {
        cin >> n;
        int x, y;
        x = n, y = 2 * n;
        cout << x << ' ' << y << '\n';
    }
    return 0;
}

C.优美的序列

思路:

一种猜测,排完序检查每一对是否符合条件,试想一下排完序的序列,如果本来|a_i -a_j|就很大,那么他们间得距离也尽可能大,如果先将他们放近,就有可能|a_i -a_j|小的反而只能间距很大就不符合要求了。

代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 100010,mod = 1e6+7;
typedef long long ll;
typedef pair<int,int> pii;

int n,m,k;

void solve()
{
    cin >> n;
    vector<int> a(n);
    for(auto &x : a) cin >> x;
    sort(a.begin(), a.end());
    for(int i = 0;i < n; i++ )
        for(int j = i + 1;j < n; j++ )
            if(a[j] - a[i] < j - i)
            {
                cout << -1 << '\n';
                return ;
            }
    for(auto &x : a)
        cout << x << ' ';
    cout << '\n';
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    T = 1;
    cin >> T;
    while(T--) solve();
    return 0;
}

D.E Kevin喜欢零

思路:

可以看不懂我的可以去看看牛牛的题解

【题解】牛客小白月赛73_ICPC/CCPC/NOIP/NOI刷题训练题单_牛客竞赛OJ

求某个区间的乘积的数的末尾0的个数,10 = 2 * 5,那么可以提供的末尾0的个数等于min(质因子2的个数,质因子5的个数),我们可以维护两个质因子的前缀和可以在O(1)的计算某个连续子区间乘积的后导零的数量,我们可以枚举右端点r,使用l_1,l_2分别维护合法的最小边界区间和合法的最大区间边界

例如:n = 5,k = 2,r = 5时,

 

l_1不能在向右移动,如果在向有移动,区间乘积后导零的个数就小于2了;l_2不能在向左移动,因为再向左移动,区间乘积后导零个数就大于2了。

对于每个右端点,计算对答案的贡献即可。

代码

#include<bits/stdc++.h>

using namespace std;

const int N = 200010,mod = 1e6+7;
typedef long long ll;
typedef pair<int,int> pii;

int n,m,k;
ll a[N],a2[N],a5[N];

void solve()
{
    cin >> n >> k;
    for(int i = 1;i <= n; i++ )
        a2[i] = a5[i] = 0;
    for(int i = 1;i <= n; i++ )
    {
        cin >> a[i];
        while(a[i] % 2 == 0 && a[i] != 0) a2[i]++, a[i] /= 2;
        while(a[i] % 5 == 0 && a[i] != 0) a5[i]++, a[i] /= 5;
    }
    
    ll ans = 0;
    a2[n+1] = a5[n+1] = 1e18;
    for(int i = 1; i<= n; i++ )
    {
        a2[i] += a2[i - 1];
        a5[i] += a5[i - 1];
    }
    int l = 0, r = 0;
    for(int i = 1;i <= n; i ++ )
    {
        //寻找区间乘积后导零小于k的下标
        while(min(a2[i] - a2[r], a5[i] - a5[r]) >= k && r < i) r++; 

        //寻找区间乘积后导零等于k的第一个下标
        while(min(a2[i] - a2[l], a5[i] - a5[l]) > k && l < r) l++;
        ans += min(r - l, n);
    }
    cout << ans << '\n';
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    T = 1;
    cin >> T;
    while(T--) solve();
    return 0;
}

二分的做法

枚举左端点,找到第一个符合区间乘积的后导零等于k的位置设它为l_1,还需要找到第一个符合区间乘积的后导零大于k的位置设它为l_2,那么该端点的贡献值就为l_2-l_1。注意一个点,n这个位置可能取得到,那么设n+1这个位置为无穷大。

#include<bits/stdc++.h>

using namespace std;

const int N = 200010,mod = 1e6+7;
typedef long long ll;
typedef pair<int,int> pii;

int n,m,k;
ll a[N],a2[N],a5[N];

void solve()
{
    cin >> n >> k;
    for(int i = 1;i <= n; i++ )
        a2[i] = a5[i] = 0;
    for(int i = 1;i <= n; i++ )
    {
        cin >> a[i];
        while(a[i] % 2 == 0 && a[i] != 0) a2[i]++, a[i] /= 2;
        while(a[i] % 5 == 0 && a[i] != 0) a5[i]++, a[i] /= 5;
    }
    
    ll ans = 0;
    a2[n+1] = a5[n+1] = 1e18;
    for(int i = 1; i<= n; i++ )
    {
        a2[i] += a2[i - 1];
        a5[i] += a5[i - 1];
    }
    a2[n + 1] = 1e9, a5[n + 1] = 1e9; //有可能会跑到r+1,因为n这个位置是有可能符合条件的
    for(int i = 1;i <= n; i ++ )
    {
        int l1,r1,l2,r2;
        l1 = i, r1 = n + 1;
        while(l1 < r1) //去找第一个符合区间乘积后导零为k的位置
        {
            int mid = (l1 + r1) / 2;
            if(min(a2[mid] - a2[i - 1], a5[mid] - a5[i - 1]) >= k) r1 = mid;
            else l1 = mid + 1;
        }
        l2 = i, r2 = n + 1;
        while(l2 < r2) //去找第一个符合区间乘积后导零大于k的位置
        {
            int mid = (l2 + r2) / 2;
            if(min(a2[mid] - a2[i - 1], a5[mid] - a5[i - 1]) > k) r2 = mid;
            else l2 = mid + 1;
        }
        // cout << l1 << ' ' << l2 << endl;
        ans += l2 - l1;
    }

    cout << ans << '\n';
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    T = 1;
    cin >> T;
    while(T--) solve();
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值