牛客寒假算法基础集训营6(部分)

比赛传送门:点我

A题:出题

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

小B准备出模拟赛。
她把题目按难度分为四等,分值分别为6,7,8,9。
已知小B共出了m道题,共n分。
求小B最少出了多少道6分题。    

输入描述:

两个正整数n,m

输出描述:

一个数,表示答案。
若无解,输出"jgzjgzjgz"。
示例1

输入

34 5

输出

1
示例2

输入

32 5

输出

3
示例3

输入

5 1

输出

jgzjgzjgz

思路:
读完题目,感觉是个解方程的题。首先确定无解的情况:m*6>n或者m*9<n 即:n太小了,全都用6都凑不齐或者n太大了,全都用9都凑不到那么大。

再讨论可以的情况。在可以的情况下,n可以先减去6*m。那么题目就变成了用0、1、2、3,这四个数,使用m次凑成n-m*6。(肯定能凑成,因为有0存在)
因为题目要求的是,使用6的最少次数,转换到上面的场景,就是使用0的最少次数。
思路转变为,用尽量多的次数,1、2、3三个数凑成n-m*6。那么用0就变少了。
一个三可以变成1,2,3个贡献(3,1+2,1+1+1)
两个三可以变成[2,9]里面任何的一个。
k个三可以变成[k,3*k]里面任何一个。
假设刚开始使用最多个3,其他的用1来填补,分别用Use_1,use_3表示使用了3和1的个数。
use_3 = (n-m*6)/3, use_1 = n-n3*3;
然后开始拆掉3。
分两种情况:m-use_1>=3*use_3。就是把全部的3拆了都不够,剩下的就用0来填了。
      m-use_1在[use_3,3*use_3]这个区间里面,则不需要0了,已经可以用3拆出所需要的。
代码:
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f
#define MM(x) memset(x,0,sizeof(x))
#define MMINF(x) memset(x,INF,sizeof(x))
typedef long long LL;
int main()
{
    LL n,m;
    cin>>n>>m;
    if(m*6 > n || m*9 < n){
        puts("jgzjgzjgz");
    }
    else{
        n = n-m*6;
        LL n3 = n/3;
        LL n1 = n-n3*3;
        LL k;
        if(3*n3 <= m-n1){
            k = m-n1-3*n3;
        }
        else if ((m-n1)>=n3 && (m-n1)<=3*n3){
            k = 0;
        }
        else{
            return puts("jgzjgzjgz"),0;
        }
        printf("%lld\n",k);
    }
}
/*
90000000000
14000000007
*/


B题:链接:https://ac.nowcoder.com/acm/contest/332/B
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

小j开始打工,准备赚钱买煤气灶。
第一天,小j的工资为n元,之后每天他的工资都比前一天多d元。
已知煤气灶需要m元,求小j最少工作几天才能买到煤气灶。

输入描述:

四个整数 n,m,d,x
分别表示小j第一天的工资,煤气灶的价格,工资每天的增长量,答案不超过x

输出描述:

一个数表示答案
示例1

输入

10 100 20 100

输出

4

说明

10+30+50+70>=100

备注:

0n,d10^9,n+d>0 

思路:暴力就完事了。
代码:
#include<bits/stdc++.h>
typedef long long LL;
int main()
{
    LL n,m,d,x;
    cin>>n>>m>>d>>x;
    LL k = 1,dep = n,now = n;
    while(true){
        if(k > x)break;
        if(now >= m)break;
        k++;
        dep = n+(k-1)*d;
        now += dep;
    }
    printf("%lld\n",k);
}

C题:项链

链接:https://ac.nowcoder.com/acm/contest/332/C

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小B想给她的新项链染色。
现在有m种颜色,对于第i种颜色,小B有a_i单位的颜料,每单位颜料可以染项链的一个珠子;
同时,小B对于第i种颜色的喜爱度为b_i。
已知项链有n个珠子,求染色后每个珠子的颜色的喜爱度之和的最大值。
(每个珠子只能至多被染一次,不被染色则喜爱度为0)    

输入描述:

第一行两个数n,m
第二行m个数a_i
第三行m个数b_i

输出描述:

一个数表示答案
示例1

输入

5 3
1 2 3
3 2 1

输出

9
示例2

输入

5 3
1 2 1
3 2 1

输出

8

备注:

1n,m10^5,0ai,bi10^6

思路:简单贪心,先选价值大的。
代码:
#include<bits/stdc++.h>
typedef long long LL;
struct node{
    int a,b;
}p[100001];
bool cmp(node x,node y){
    return x.b>y.b;
}
int main()
{
    int n,m;cin>>n>>m;
    for(int i = 0 ; i < m ; i ++){
        scanf("%d",&p[i].a);
    }
    for(int i = 0 ; i < m ; i ++){
        scanf("%d",&p[i].b);
    }
    int k = 0;
    LL ans = 0;
    sort(p,p+m,cmp);
    while(n > 0){
        if(n >= p[k].a){
            n -= p[k].a;
            ans += p[k].a*p[k].b*1LL;
        }
        else if(n < p[k].a){
            ans += (n)*p[k].b*1LL;
            n = 0;
        }
        k++;
        if(k == m)break;
    }
    printf("%lld\n",ans);
}
/*
5 3
1 2 3
3 2 1
*/
 
     

 D题:美食

链接:https://ac.nowcoder.com/acm/contest/332/D
时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小B喜欢美食。
现在有n个美食排成一排摆在小B的面前,依次编号为1..n,编号为i的食物大小为 a[i] ,即足够小B吃 a[i] 口。
小B每次会吃两口,这两口要么是编号相同的美食,要么是编号之差的绝对值为1的美食。
小B想知道,她最多能吃几次?

输入描述:

第1行一个正整数n,表示美食个数
接下来n行,第i行一个整数a[i],表示编号为i的美食的大小

输出描述:

一个数表示小B最多吃几次。
示例1

输入

4
1
5
7
8

输出

10

说明

用二元组(a,b)表示某一次吃的两个美食分别为第a个美食和第b个美食,则下面为一个吃10次的方案:
(1,2)(2,2)(2,2)(3,4)(3,4)(3,4)(3,4)(3,4)(3,4)(3,4)
注意不一定要吃完。


思路:
考虑一下相邻都-1,和自己本身-2,那么最后的串可以变为01串(比如说4231能变为0011,其实是本身去不断的-2)
考虑串323,中间的2可以跟左边和右边的3分别消去一次,即323这种奇数偶数奇数的串可以消去4次。
再考虑串3223,即奇偶偶奇,同样也能最后变为0000(3223->2123->2112->2002->0000)
再考虑串32223,也能消成00000。
即如果是1x1 其中x为若干偶数,即可消掉左边和右边的1,让次数+1。(有特殊情况)
特殊情况:如果本身没变成01串之前原位置就是0,例如30003这种通过自身尽量-2,变为10001,左右两边的1是不能消去的。
代码:
#include<bits/stdc++.h>
typedef long long LL;
int a[100001];
int main()
{
    LL ans = 0;
    int n;cin>>n;
    for(int i = 0 ; i < n ; i++){
        cin>>a[i];
        if(a[i] == 0)a[i] = -1;//如果本身是0,那么记为-1
        ans += (a[i]/2)*1LL;//尽量让自己通过-2变为最简
        a[i] = a[i]%2;
    }
    int flag = 0;
    for(int i = 0 ; i < n ; i ++){
        if(a[i] == -1){
            flag = 0;
            continue;
        }
        if(a[i] == 1 && flag == 0){
            flag = 1;
            continue;
        }
        if(a[i] == 1 && flag == 1){
            flag = 0;
            ans++;
        }//找到可以消去的1,次数+1
    }
    printf("%lld\n",ans);
}

G题:区间或和
链接:https://ac.nowcoder.com/acm/contest/332/G
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

 
     
求a|(a+1)|(a+2)|...|(b-1)|b。

其中|表示[按位或](https://baike.baidu.com/item/%E6%8C%89%E4%BD%8D%E6%88%96)。

输入描述:

多组输入,每行两个数表示a和b

输出描述:

对于每组输入,输出一个数a|(a+1)|(a+2)|...|(b-1)|b。
示例1

输入

99 109
68 77
55 66
34 43
1111234 1114321

输出

111
79
127
47
1179647

思路:
看到或,想到的肯定是二进制。
那么就好做了,看以下例子:(括号2表示2进制情况)
0000100(2)
1010000(2)
答案是1111111(2) ,因为中间肯定有个数是111111,即可以后面全部为1
000101(2)
101111(2)
答案是111111(2),因为中间肯定有个数是11111,即也可以全部为1
第一种情况是,两个二进制数位数不等的情况下,那么就是大的那个数全补1,原因是肯定能从上个1111-->10000,即可以补齐全部1
第二种情况是,位数相等。
例子:
1000100(2)
1010000(2)
答案是1011111(2),因为在从左往右数第三个位置大的数是1,所以后面的都能补齐
在这种情况下,稍微多看几个例子就会发现,可以抛去第一位,然后如果小的数和大的数对应位置都是0,那么这位是1,一旦大的数某一位是1,后面的全部是1.
到此就分析完了。
代码:(java大数写的,只给主要代码)
 Scanner input = new Scanner(System.in);
     while(input.hasNext()){
         BigInteger a = input.nextBigInteger();
         BigInteger b = input.nextBigInteger();
         String s = a.toString(2);
         String s1 = b.toString(2);
         String s2 = "";
         if(s1.length() > s.length()){
             BigInteger ans = BigInteger.valueOf(2);
             for(int i = 0 ; i < s1.length()-1 ; i ++){
                 ans = ans.multiply(BigInteger.valueOf(2));
             }
             ans = ans.subtract(BigInteger.ONE);
             System.out.println(ans);
         }//位数不等
         else{
              int flag = 0;
              for(int i = 0 ; i < s.length();i++){
                 char p1 = s.charAt(i);
                 char p2 = s1.charAt(i);
                 if(flag == 2){
                     s2 = s2+"1";continue;
                 }
                 if(p1 == p2 && p1 == '0'){
                     s2 = s2+"0";flag = 1;
                 }//如果都是0,则该位是0
                 else{
                     s2 = s2+"1";
                     if(p2=='1'&&p1=='0')flag = 2;//一旦出现大的串是1的情况,则后面的都是1
                 }
             }
             BigInteger c = new BigInteger(s2,2);//二进制转十进制
             System.out.println(c);
         }
     }
 
     

G:迷宫
链接:https://ac.nowcoder.com/acm/contest/332/J
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
 
     

题目描述

 
     
你在一个 n 行 m 列的网格迷宫中,迷宫的每一格要么为空,要么有一个障碍。
你当前在第 r 行第 c 列(保证该格子为空)。每次移动你可以向上下左右任意一个方向移动一格,前提是不能走到障碍上,也不能超出迷宫的边界。
你向左移动的次数不能超过 x 次,向右不能超过 y 次。
问在这种情况下,对于每个格子,是否存在一种移动方案让你走到它。
输出有多少个格子存在移动方案让你走到它。

输入描述:

第一行两个正整数 n,m 。
第二行两个正整数 r,c ,保证 1rn1≤r≤n ,1cm1≤c≤m 。
第三行两个整数 x,y ,保证 0x,y1090≤x,y≤109 。
接下来 n 行,每行一个长度为 m 的字符串,
第 i 行第 j 个字符表示迷宫第 i 行第 j 列的格子,
字符为`.` 表示格子为空,字符为`*` 表示格子上有一个障碍。

输出描述:

输出一个数,表示有多少个格子存在移动方案让你走到它。
示例1

输入

4 5
3 2
1 2
.....
.***.
...**
*....

输出

10

说明

将能走到的格子用+标记:

+++..
+***.
+++**
*+++.
示例2

输入

4 4
2 2
0 1
....
..*.
....
....

输出

7

说明

.++.
.+*.
.++.
.++.


思路:广搜就完事了,注意限制条件有左移右移距离,其实就是加个判断。
代码:
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f
#define MM(x) memset(x,0,sizeof(x))
#define MMINF(x) memset(x,INF,sizeof(x))
typedef long long LL;
char mp[1001][1001];
bool vis[1001][1001];
int n,m,r,c,bx,by;
struct node{
    int x,y,left,right;
    node(){}
    node(int x,int y,int left,int right)
        :x(x),y(y),left(left),right(right){}
};
bool judge(int x,int y,int L,int R){if(vis[x][y] || x < 0 || x >= n || y < 0 || y >= m || L > r || R > c || mp[x][y] == '*')
        return false;
    return true;
}
void bfs(){
    queue<node>q;
    node a(bx,by,0,0);
    q.push(a);
    vis[bx][by] = 1;
    while(!q.empty()){
        int dx,dy,L,R;
        node u = q.front();q.pop();
        dx = u.x + 1; dy = u.y;
        L  = u.left;
        R  = u.right;
        if(judge(dx,dy,L,R)){
            node v(dx,dy,L,R);
            vis[dx][dy] = 1;
            q.push(v);
        }
        //
        dx = u.x - 1; dy = u.y;
        L  = u.left;
        R  = u.right;
        if(judge(dx,dy,L,R)){
            node v(dx,dy,L,R);
            vis[dx][dy] = 1;
            q.push(v);
        }
        //
        dx = u.x; dy = u.y - 1;
        L  = u.left+1;
        R  = u.right;
        if(judge(dx,dy,L,R)){
            node v(dx,dy,L,R);
            vis[dx][dy] = 1;
            q.push(v);
        }
        //
        dx = u.x; dy = u.y + 1;
        L  = u.left;
        R  = u.right+1;
        if(judge(dx,dy,L,R)){
            node v(dx,dy,L,R);
            vis[dx][dy] = 1;
            q.push(v);
        }
        //
    }
}
int main()
{
     cin>>n>>m>>bx>>by>>r>>c;
     memset(vis,0,sizeof(vis));
     for(int i = 0 ; i < n ; i ++){
         scanf("%s",mp[i]);
    }
    bx-=1;by-=1;
    bfs();
    int ans = 0;
    for(int i = 0 ; i < n ; i ++){
        for(int j = 0 ; j < m ; j++){
            if(vis[i][j] == 1){
                ans++;
            }
        }
    }
    printf("%d\n",ans);
}
/*
4 5
3 2
1 2
.....
.***.
...**
*....
*/
 
      
     


猜你喜欢

转载自www.cnblogs.com/Esquecer/p/10348883.html