0
点赞
收藏
分享

微信扫一扫

牛客寒假算法基础集训营6 题解


 

牛客寒假算法基础集训营6 题解

A出题

链接:​​https://ac.nowcoder.com/acm/contest/332/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

备注:

n,m≤1012

分析:

无解:6m>n或n>9m 。

有解:

设6,7,8,9分的题数为a,b,c,d,

则:

n=6a+7b+8c+9d

m=a+b+c+d

得出,

a=7*m-n+c+2*d

7*m-n是固定的,c+2*d是随便的数,因为我们知道我们这种情况肯定有解。

所以a的最小值为7*m-n

官方题解:

牛客寒假算法基础集训营6 题解_java

import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
//Scanner in = new Scanner (new BufferedInputStream(System.in));
Scanner in = new Scanner(new BufferedInputStream(System.in));

Long n=in.nextLong();
Long m=in.nextLong();
if(n<6*m||n>9*m)
{System.out.println("jgzjgzjgz");return ;}

Long ans=(long) (1<<30);
if(7*m-n>=0)
System.out.println(7*m-n);
else
System.out.println(0);



}
}

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

备注:

0≤n,d≤109,n+d>00≤n,d≤109,n+d>0
1≤m≤10181≤m≤1018
1≤x≤109

我的解直接二分的答案

官方题解:

牛客寒假算法基础集训营6 题解_i++_02

import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
//Scanner in = new Scanner (new BufferedInputStream(System.in));
Scanner in = new Scanner(new BufferedInputStream(System.in));

Long n=in.nextLong();
Long m=in.nextLong();
Long d=in.nextLong();
Long x=in.nextLong();
Long l=(long) 1;
Long r=x;
while(l<r)
{
Long mid=(l+r)>>1;
Long f=mid*n+mid*(mid-1)/2*d;
if(f>=m)
{
r=mid;
}
else
l=mid+1;
}
System.out.println(l);


}
}

 

C项链

很裸的贪心

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAX 20007

using namespace std;
struct node
{
int x,y;

}a[100005];
bool cmp(node q,node w)
{
return q.y>w.y;
}
int main ( )
{
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
scanf("%d",&a[i].x);
for(int i=1;i<=m;i++)
scanf("%d",&a[i].y);
sort(a+1,a+m+1,cmp);
long long ans=0;
for(int i=1;i<=m&&n>0;i++)
{
//cout<<a[i].x<<" "<<a[i].y<<" "<<n<<endl;
if(n>=a[i].x)
{
ans=ans+(long long)(a[i].x*a[i].y);
n-=a[i].x;
}
else
{
ans=ans+(long long)((n)*a[i].y);
break;
}

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

D美食

贪心

i从1到n枚举,依次贪心。

对于a[i],

首先把答案加上a[i]/2,

如果a[i]是奇数且a[i+1]>0,则把a[i+1]减去1,答案加上1。

import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
//Scanner in = new Scanner (new BufferedInputStream(System.in));
Scanner in = new Scanner(new BufferedInputStream(System.in));
Long []a=new Long[100005];
Long n=in.nextLong();
for(int i=1;i<=n;i++)
{
a[i]=in.nextLong();
}
Long ans=(long) 0;
a[(int) (n+1)]=(long) 0;
for(int i=1;i<=n;i++)
{
ans+=a[i]/2;
if(a[i]%2==1&&a[i+1]!=0)
{a[i+1]--;ans++;}
}
System.out.println(ans);



}
}

 

海啸

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

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

题目描述

有一个沿海地区,可以看作有n行m列的城市,第i行第j列的城市海拔为h[i][j]。
由于沿海,所以这个地区经常会发生海啸。
海啸发生时,部分城市会被淹没,具体来说,海水高度会达到d,因此海拔低于d的城市都会被淹没。
现在有q次询问,每次问你一个矩形区域中,有多少城市不会被淹没。

输入描述:

第一行三个整数n,m,d,具体含义见题目描述。
接下来n行,每行m个整数,其中第i行第j列的整数为h[i][j],具体含义见题目描述。
第n+2行一个整数q,表示询问数。
接下来q行,每行四个整数a,b,x,y,
表示询问从第a行第b列到第x行第y列的矩形地区中,有多少地区不会被淹没。
即有多少个i,j,满足 a≤i≤x,b≤j≤ya≤i≤x,b≤j≤y ,且 h[i][j]≥dh[i][j]≥d 。

输出描述:

共q行,第i行一个整数,表示第i个询问的答案。

示例1

输入

复制

3 3 3
1 2 3
2 1 5
4 3 2
2
1 2 2 3
2 1 3 3

输出

复制

2
3

备注:

1≤n×m≤1061≤n×m≤106
1≤q≤1051≤q≤105
0≤d,h[i][j]≤1090≤d,h[i][j]≤109
1≤a≤x≤n,1≤b≤y≤m

运用一个二维前缀和即可


 

 

牛客寒假算法基础集训营6 题解_System_03

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.StringTokenizer;
public class Main {

public static void main(String[] args) throws IOException {
//Scanner in = new Scanner (new BufferedInputStream(System.in));
Scanner in = new Scanner(new BufferedInputStream(System.in));
Reader.init(System.in);
int n=Reader.nextInt();
int m=Reader.nextInt();
int d=Reader.nextInt();
int [][]sum=new int[n+1][m+1];

for(int i=1;i<=n;i++)
{
sum[i]=new int[m+1];
for(int j=1;j<=m;j++)
{
int x=Reader.nextInt();
if(x>=d)
sum[i][j]=1;
else
sum[i][j]=0;
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
int q=Reader.nextInt();
while(q-->0)
{
int l1=Reader.nextInt(),r1=Reader.nextInt(),l2=Reader.nextInt(),r2=.nextInt();
int ans=sum[l2][r2] + sum[l1 - 1][r1 - 1] - sum[l1 - 1][r2] - sum[l2][r1 - 1];
System.out.println(ans);
}


// System.out.println(ans);




}
}
class Reader
{
static BufferedReader reader;
static StringTokenizer tokenizer;

static void init(InputStream input)
{
reader = new BufferedReader(new InputStreamReader(input));
tokenizer = new StringTokenizer("");
}

static String next() throws IOException
{
while(!tokenizer.hasMoreTokens())
{
String str=reader.readLine();
//System.out.println(str);
tokenizer = new StringTokenizer(str);
}
return tokenizer.nextToken();
}

static int nextInt() throws IOException
{
return Integer.parseInt(next());
}

static double nextDouble() throws IOException
{
return Double.parseDouble(next());

}
}

石头剪刀布

待补

根据获胜者的偏爱决策可以推出对战的两人的偏爱决策,所以枚举最终获胜者的偏爱决策判断一下就好了。字典序问题只需递归处理+暴力 cmp 。

时间 O(2n×n)O(2n×n)

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

备注:

输入不超过10000行,0≤a,b≤10180≤a,b≤1018,a≤b

规律题:

发现当一个数按位或一个比它大的数的时候它才会变,那么我们对于a和b,依次枚举ans按位或ans+1,直到大于等于b就好了。

官方题解:

牛客寒假算法基础集训营6 题解_i++_04

 

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int main()
{
ll a,b;
while(scanf("%lld%lld",&a,&b) != EOF){

while(a < b){
a|= (a + 1);
}
printf("%lld\n", a);
}
return 0;
}

肥猪

待补

从0到n-1枚举第二种操作的使用次数step,

那么对于最终得到的编号为i的肥猪,

假如它是召唤编号为j的肥猪然后进化多次得到的,

则一定有 i−step≤j≤ii−step≤j≤i ,

并且这是充要的,即它可以由这个区间的任何一个j召唤后进化多次得到。

因此只用这个区间的a[j]的最小值就是得到i的代价。

把所有i的代价相加再加上step*x就是step对应的最小代价。

注意,这个题目是一个环而不是链,这只需要将a复制一份即可。

求区间最小值有很多方法,比如单调队列。

时间复杂度 O(n2)O(n2) 。

I wzoi

链接:​​https://ac.nowcoder.com/acm/contest/332/I​​​ 来源:牛客网
 

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

题目描述

bleaves 最近在 wzoi 上面做题。
wzoi 的题目有两种,一种是 noip 题,一种是省选题。
bleaves 的做题方式很特别。每一天,她可能会看一道题目,这时她会选择题目种类,然后 wzoi 会在选定种类中随机扔给她一道她还没看过的题,她会把这道题看一遍,然后存在脑子里慢慢思考;她也有可能写题,这时她一定会写没写过的题中看的时间最迟的一题(如果不存在没写过的且没看过的题,她就不能写题)。
wzoi 每天会有一个推荐的题目种类,
如果 bleaves 看一道题目:如果种类和推荐的相同,那么这道题目最大得分为10,否则为5
如果 bleaves 写一道题目:如果种类和推荐的相同,那么这道题目得分为最大得分,否则为最大得分-5
假如 bleaves 现在还没看过任何一题,并且她知道了 wzoi 接下来一些天每天推荐的种类,问她在这些天的最大得分。

输入描述:

一行一个01串 s ,|s| 表示天数,si=0si=0 表示 wzoi 第 i 天推荐 noip 题, si=1si=1 表示 wzoi 第 i 天推荐省选题。

输出描述:

一行一个整数最大得分。

示例1

输入

复制

0011

输出

复制

20

说明

4天行动依次为:看一道 noip 题,写第1天看的题,看一道省选题,写第3天看的题。

示例2

输入

复制

0101

输出

复制

10

说明

4天行动依次为:看一道 noip 题,写第1天看的题,看一道noip题,写第3天看的题。

示例3

输入

复制

0110

输出

复制

20

说明

4天行动依次为:看一道 noip 题,看一道省选题,写第2天看的题,写第1天看的题。

备注:

全部的输入数据满足:1≤n≤1061≤n≤106 , n 为偶数。

分析:

其实这题算一个贪心,因为它要做最后看到的题,最优的策略00 11就能得到10分,删除他们,剩下的能得到5分,用栈模拟一个删除过程即可

牛客寒假算法基础集训营6 题解_i++_05

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.Stack;
import java.util.StringTokenizer;
public class Main {

public static void main(String[] args) throws IOException {
//Scanner in = new Scanner (new BufferedInputStream(System.in));
Scanner in = new Scanner(new BufferedInputStream(System.in));
Reader.init(System.in);
char[] s=in.next().toCharArray();
int ans=0;
int cnt=0;
Stack<Character> s1=new Stack<Character>();
for(int i=0;i<s.length;i++)
{
if(s1.size()==0)
{
s1.push(s[i]);
continue;
}
if(s[i]==s1.peek())
{
s1.pop();
ans+=10;
}
else
{
s1.push(s[i]);
}
}
ans=ans+s1.size()/2*5;
System.out.println(ans);
}
}
class Reader
{
static BufferedReader reader;
static StringTokenizer tokenizer;

static void init(InputStream input)
{
reader = new BufferedReader(new InputStreamReader(input));
tokenizer = new StringTokenizer("");
}

static String next() throws IOException
{
while(!tokenizer.hasMoreTokens())
{
String str=reader.readLine();
//System.out.println(str);
tokenizer = new StringTokenizer(str);
}
return tokenizer.nextToken();
}

static int nextInt() throws IOException
{
return Integer.parseInt(next());
}

static double nextDouble() throws IOException
{
return Double.parseDouble(next());

}
}

J迷宫

链接:​​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 ,保证 1≤r≤n1≤r≤n ,1≤c≤m1≤c≤m 。
第三行两个整数 x,y ,保证 0≤x,y≤1090≤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

说明

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

备注:

对于全部数据, 1≤n,m≤10001≤n,m≤1000 。

 

这题简单的bfs就能过

不过题解给了啥:

这题数据

牛客寒假算法基础集训营6 题解_i++_06

 

import java.io.BufferedInputStream;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
class node
{
int x,y,ls,rs;

public node(int x, int y, int ls, int rs) {
super();
this.x = x;
this.y = y;
this.ls = ls;
this.rs = rs;
}

@Override
public String toString() {
return "node [x=" + x + ", y=" + y + ", ls=" + ls + ", rs=" + rs + "]";
}



}
public class Main {
static int [] dx={1,0,-1,0};
static int [] dy={0,1,0,-1};
static int n,m,x,y;
static String[] map =new String[1005];
static int[][] vis =new int[1005][1005];
public static int bfs(int x1,int y1)
{
Queue<node> q=new LinkedList<node>();
node a = new node(x1,y1,0,0);
q.offer(a);
int ans=1;
vis[x1][y1]=1;
while(q.size()!=0)
{

a=q.poll();
//System.out.println(a);
for(int i=0;i<4;i++)
{
node b=null;
if(i==1)
{
b=new node(a.x+dx[i],a.y+dy[i],a.ls,a.rs+1);
}
else if(i==3)
b=new node(a.x+dx[i],a.y+dy[i],a.ls+1,a.rs);
else
b=new node(a.x+dx[i],a.y+dy[i],a.ls,a.rs);
if(b.x>=0&&b.x<n&&b.y>=0&&b.y<m&&map[b.x].charAt(b.y)!='*'&&b.ls-b.rs<=x&&b.rs-b.ls<=y&&vis[b.x][b.y]==0)
{
ans++;
q.offer(b);
vis[b.x][b.y]=1;
}

}
}
return ans;
}
public static void main(String[] args) {
//Scanner in = new Scanner (new BufferedInputStream(System.in));
Scanner in = new Scanner(new BufferedInputStream(System.in));

n=in.nextInt();
m=in.nextInt();
int r=in.nextInt();
int c=in.nextInt();
r--;
c--;
x=in.nextInt();
y=in.nextInt();
in.nextLine();

for(int i=0;i<n;i++)
{
map[i]=new String();
map[i]=in.next();
}
System.out.println(bfs(r,c));




}
}

 

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

#define rep(i,l,r) for(int i=l;i<=r;++i)

const int N=2000+5,inf=1e9;
char s[N][N];
int g[N][N];
deque<int>q;
int n,m,r,c;

void bfs()
{
rep(i,1,n)
rep(j,1,m)g[i][j]=inf;
g[r][c]=0;
q.push_back(r*N+c);
while(!q.empty())
{
int x=q.front();q.pop_front();
int y=x%N;x/=N;
if(s[x-1][y]=='.'&&g[x-1][y]>g[x][y])
{
g[x-1][y]=g[x][y];
q.push_front((x-1)*N+y);
}
if(s[x+1][y]=='.'&&g[x+1][y]>g[x][y])
{
g[x+1][y]=g[x][y];
q.push_front((x+1)*N+y);
}
if(s[x][y-1]=='.'&&g[x][y-1]>g[x][y]+1)
{
g[x][y-1]=g[x][y]+1;
q.push_back(x*N+y-1);
}
if(s[x][y+1]=='.'&&g[x][y+1]>g[x][y]+1)
{
g[x][y+1]=g[x][y]+1;
q.push_back(x*N+y+1);
}
}
}

int main()
{
//freopen("1.in","r",stdin);//freopen("1.out","w",stdout);
cin>>n>>m>>r>>c;
int x,y;
cin>>x>>y;
rep(i,1,n)scanf("%s",s[i]+1);
bfs();
int ans=0;
rep(i,1,n)
rep(j,1,m)
if(g[i][j]!=inf)
{
int a=j-c;
int b=g[i][j];
ans+=(b-a)/2<=x&&(b+a)/2<=y;
}
cout<<ans;
}

std

​​https://ac.nowcoder.com/acm/contest/332#submit/{%22searchUserName%22%3A%22kczno1%22}​​

举报

相关推荐

0 条评论