ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

牛客小白月赛40

2021-11-07 23:32:36  阅读:287  来源: 互联网

标签:题意 int 小白月赛 40 牛客 ans using include dp


A.数字游戏

题意:

我们可以对一个非零数的二进制进行以下操作:

1.若二进制中有奇数个1,我们将其二进制最低位取反

2.若二进制中有偶数个1,我们将其二进制中非前导0最高位取反。

问给你个数x,需要操作几次变成0.

思路:

先把数转换为二进制,通过枚举找到规律如下:

令该数为n,其二进制中1的个数为x。

1.若n为0,ans = 0。

2.若n为偶数,且x也为偶数,则ans = 2 * x。

3.若n为偶数,且x为奇数,则ans = 2 * x - 2。

4.若n为奇数,且x为奇数,则ans = 2 * x - 1。

5.若n为奇数,且x为偶数,则ans = 2 * x + 1。

 

代码:

#include <bits/stdc++.h>
typedef long long LL;

using namespace std;

int work(LL n)
{
    int ans = 0;
    while(n)
    {
        if(n % 2 == 1) ans ++;
        n /= 2;
    }
    return ans;
}

void solve()
{
    LL n;
    scanf("%lld",&n);
    int ans = 0;
    int x = work(n);
    if(n == 0){
        ans = 0;
    }
    else if(x % 2 == 0){
        if(n % 2 == 0) ans = 2 * x;
        else ans = 2 * x - 2;
}
    else 
    {
        if(n % 2 == 0){
            ans = 2 * x + 1;
        }else{
            ans = 2 * x - 1;
        }
    }
    printf("%d\n",ans);
}

int main()
{
    int T = 1;
    scanf("%d",&T);
    while(T -- )
    {
        solve();
    }
    return 0;
}

 B.跳跳跳

题意:

有一个n个格子呈环状分布,每个格子都有一个权值a[i],dd可以选择任意一个格子开始跳,每次只能跳到其当前位置左边或者右边最近的且未被跳过的位置,每次获得 k * a[i]的得分,k为当前跳跃次数,a[i]为当前格子上的权值。问如何跳使得总得分最大,求出最大总分。

思路:

这是一个区间dp。dd左右跳形成一个个区间,我们令dp[i][j]表示从编号为i的格子跳到编号为j的格子中得分最大。

很明显状态转移只有两种情况:

1.从dp[i +1][j] ——> dp[i[j]

2.从dp[i][j - 1] ——> dp[i][j]

所以 dp[i][j] = max(dp[i + 1][j] + a[i] * (j - i + 1), dp[i][j - 1] + a[j] * (j - i + 1));

然后枚举下长度为n的区间,寻找下最大值就OK。

本题是环形难以处理需要不断取模,我们可以将原数组复制成原来的两倍再加以处理。

其次是从状态转移方程来看,想要计算出dp[i][j],先必须要计算出dp[i +1][j]和dp[i][j - 1],所以外层循环要从大到小枚举,内层循环需要从小到大枚举。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

int n;
int a[4010];
LL dp[4010][4010];

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++ ) cin >> a[i], a[i + n] = a[i];
    for(int i = 1; i <= 2 * n; i ++ ) dp[i][i] = a[i];
    for(int i = 2 * n; i >= 1; i -- )
        for(int j = i + 1; j <= n + i - 1; j ++ )
            dp[i][j] = max(dp[i + 1][j] + a[i] * (j - i + 1), dp[i][j - 1] + a[j] * (j - i + 1));

    LL ans = -1;
    for(int i = 1; i <= n + 1; i ++ )   ans = max(ans, dp[i][n + i - 1]);
    cout << ans << endl;
    return 0;
}

C.数字匹配

题意:

对于任意两个正整数x,y(x≠y),当且仅当x,y的二进制非前导零部分最大连续重合位数≥k时,x,y是匹配的。

让你寻找1~n中x与y的匹配数,x < y。

思路:

暴力处理1~n中所有数的二进制,再暴力查找匹配的x,y的数目。

代码:

#include <bits/stdc++.h>

using namespace std;

int n, k;
string a[2010];

vector<int> binary(int n)
{
    vector<int>q;
    while(n)
    {
        q.push_back(n % 2);
        n /= 2;
    }
    reverse(q.begin(),q.end());
    return q;
}

bool check(int x, int y)
{
    for(int i = 0; i + k <= a[x].length(); i ++ )
        for(int j = 0; j + k <= a[y].length(); j ++ )
            if(a[x].substr(i, k) == a[y].substr(j, k)) return true;         
    return false;
}

int main()
{
    scanf("%d %d",&n, &k);
    for(int i = 1; i <= n; i ++ )
    {
        vector<int>q = binary(i);
        for(int j = 0; j < q.size(); j ++ ) a[i] += (q[j] + '0');
    }
    int ans = 0;
    for(int i = 1; i <= n; i ++ )
        for(int j = i + 1; j <= n; j ++ )
            if(check(i, j)) ans ++;

    cout << ans << endl;
    return 0;
}

D.优美字符串

题意:

给你个字符串,问你至少需要插入多少字符使得相邻的两个字符串不相等。

思路:

暴力枚举,统计出有多少相邻两个字符相等的数目。

#include <bits/stdc++.h>
typedef long long LL;

using namespace std;

string s;
void solve()
{
    cin >> s;
    int ans = 0;
    for(int i = 0; i + 1 < s.length(); i ++ )
    {
        if(s[i + 1] == s[i]) ans ++;
    }
    cout << ans  + s.length() << endl;
}

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

E.分组

题意:

给你n个同学,每个同学都有个声部,让你把他们分为m组,要满足每一组的声部都一样,求出所有组中的最大人数最小。若不能分组,输出”-1“。

思路:

若声部个数大于组数,无法进行分组, 输出-1。剩余情况,二分查找最小值即可。

代码:

#include <bits/stdc++.h>

using namespace std;

int n, m;
int a[100010];
bool st[100010];
map<int,int>mp;

bool check(int mid)
{
    int qwq = 0;
    for(auto it : mp){
        if(it.second % mid == 0){
            qwq += it.second / mid;
        }else{
            qwq = qwq + (it.second / mid) + 1;
        }
    }
    if(qwq > m) return false;
    return  true;
}

int main()
{
    cin >> n >> m;
    int cnt = 0;
    for(int i = 1; i <= n; i ++ )
    {
        cin >> a[i];
        if(st[a[i]] == false)
        {
            st[a[i]] = true;
            cnt ++;
        }
        mp[a[i]] ++;
    }
    if(cnt > m){
        cout << -1 << endl;
    }else{
        int l = 1, r = n;
        while(l < r)
        {
            int mid = (l + r) >> 1;
            if(check(mid)) r = mid;
            else l = mid + 1;
        }
        cout << l << endl;
    }
    return 0;
}

F.过桥

题意:

有n个浮块,dd站在第一个浮块上,每个浮块上有一个权值,dd在第i个浮块上,可以跳到i + k(k <= a[i])个浮块上,若i + a[i] < 1, 就只能移动到1浮块上,问dd最少移动几次就能到达n,如果无法到达输出-1。

思路:

我们开一个f数组,记录到每个浮块的最小次数,然后跑一边BFS即可。若f[n]为无穷大,则无法到达。否则,输出f[n]。

#include <bits/stdc++.h>

using namespace std;

int n;
int a[20100];
int f[20100];

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++ ) cin >> a[i];
    memset(f, 0x3f, sizeof f);
    queue<int>q;
    f[1] = 0;
    q.push(1);
    while(!q.empty())
    {
        int tt = q.front();
        q.pop();
        if(a[tt] > 0)
        {
            for(int i = tt + 1; i <= tt + a[tt]; i ++ )
            {
                if(f[tt] + 1 < f[i])
                {
                    f[i] = f[tt] + 1;
                    q.push(i);
                }
            }
        }
        else{
            int x = max(tt + a[tt], 1);
            for(int i = 1; i <= x; i ++ )
            {
                if(f[tt] + 1 < f[i] )
                {
                    f[i] = f[tt] + 1;
                    q.push(i);
                }
            }
        }   
    }
    if(f[n] == 0x3f3f3f3f) puts("-1");
    else cout << f[n] << endl;
    return 0;
}

G.遥控

题意:

集训队每个人都有一个温度诉求a[i],当 |a[i] - k| <= p时,算达到诉求,问dd把集训队内部的温度控制为多少,才能让更多的人达到诉求。

思路:

预处理出每个温度下,队员达到诉求的人数,再暴力枚举温度,不断取在某个温度下达到诉求的人数的最大值。

代码:

#include <bits/stdc++.h>

using namespace std;

const int N = 1000100;
int n, p;
int a[N];
int b[N];
int sum[N];

int main()
{
    cin >> n >> p;
    for(int i = 1; i <= n; i ++ )
    {
        cin >> a[i];
        b[a[i]] ++;
    }
    sum[1] = b[1];
    for(int i = 2; i <= 1000000; i ++ ) sum[i] = sum[i - 1] + b[i];
    int ans = -1;
    for(int i = p + 1; i <= n - p; i ++ )
        ans = max(ans, sum[i + p] - sum[i - p - 1]);
    cout << ans << endl;
    return 0;
}

H.来点gcd

题意:

给你一个集合S,和一个数x,问你是否能找到S的一个子集,使S中所有元素的gcd等于x。

思路:

若一个集合所有元素的gcd是x,则这个集合中的元素都是x的倍数,暴力查找出集合S中的x的倍数,然后一起取gcd,若为x,则存在,否则不存在。

若集合中x的倍数不存在,显然答案也是不存在的。

代码:

#include <bits/stdc++.h>

using namespace std;

const int N = 1000100;
int t;
int n, m;
int a[N];
bool st[1000010];

void solve()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i ++ ) st[i] = false;
    for(int i = 1; i <= n; i ++ )
    {
        scanf("%d",&a[i]);
        st[a[i]] = true;
    }
    while(m -- )
    {
        int x;
        scanf("%d",&x);
        vector<int> ans;
        for(int i = x; i <= n; i += x)
            if(st[i] == true) ans.push_back(i);
        if((ans.size() == 1 && ans[0] != x) || !ans.size())
            puts("NO");
        else if(ans.size() == 1) puts("YES");
        else
        {
            int qwq = __gcd(ans[0], ans[1]);
            for(int i = 2; i < ans.size(); i ++ ) qwq = __gcd(ans[i], qwq);
            if(qwq == x) puts("YES");
            else  puts("NO");
        }
    }
}
int main()
{
    scanf("%d",&t);
    while(t -- )
    {
        solve();
    }
    return 0;
}

I.体操队形

题意:

给你个数组a[i],体操队形要满足第i个人要站在a[i]的人的前面,问有几种站法?

思路:

暴力枚举所有站法,判断是否合法就行。

代码:

#include <bits/stdc++.h>

using namespace std;

int n;
int a[100];
int b[15];

bool check()
{
    int c[15];
    for(int i = 1; i <= n; i ++ )
    {
        for(int j = 0; j < n; j ++ )
        {
            if(b[j] == i) c[i] = j;
        }
    }
    for(int i = 1; i <= n; i ++ )
        if(c[i] > c[a[i]]) return false;
    return true;
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++ ) cin >> a[i];
    for(int i = 0; i < n; i ++ ) b[i] = i + 1;
    int ans = 0;
    do
    {
        if(check()) ans ++;
    }while(next_permutation(b, b + n));
    cout << ans << endl;
    // system("pause");
    return 0;
}

  

 

标签:题意,int,小白月赛,40,牛客,ans,using,include,dp
来源: https://www.cnblogs.com/acmerbs/p/15522305.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有