网易2019秋招笔试编程题合集(一)2020.8.7
Apare_xzc
牛客网页链接: 网易2019秋招笔试编程题合集(一)
1/7 [编程题]代价
你有3个需要完成的任务,完成这3个任务是需要付出代价的。
首先,你可以不花任何代价的完成一个任务;然后,在完成了第i个任务之后,你可以花费|Ai - Aj|的代价完成第j个任务。|x|代表x的绝对值。
计算出完成所有任务的最小代价。
分析:6种排列取最优即可
#include <bits/stdc++.h>
using namespace std;
int cal(int a,int b,int c) {
return abs(b-a)+abs(c-b);
}
int main(void) {
int a,b,c;
cin>>a>>b>>c;
int ans = 1000000;
ans = min(ans,cal(a,b,c));
ans = min(ans,cal(a,c,b));
ans = min(ans,cal(b,a,c));
ans = min(ans,cal(b,c,a));
ans = min(ans,cal(c,a,b));
ans = min(ans,cal(c,b,a));
cout<<ans<<endl;
return 0;
}
2/7 [编程题]访友
小易准备去拜访他的朋友,他的家在0点,但是他的朋友的家在x点(x > 0),均在一条坐标轴上。小易每一次可以向前走1,2,3,4或者5步。问小易最少走多少次可以到达他的朋友的家。
分析:直接dp。先大贪心,后小dp也可
#include <bits/stdc++.h>
using namespace std;
int dp[1000000+100];
int main(void) {
int x;
cin>>x;
memset(dp,0x3f,sizeof(dp));
dp[0] = 0;
for(int i=1;i<=x;++i) {
for(int j=1;j<=5&&j<=i;++j)
dp[i] = min(dp[i],dp[i-j]+1);
}
cout<<dp[x]<<endl;
return 0;
}
3/7 [编程题] 翻转翻转
给定一个N*M的矩阵,在矩阵中每一块有一张牌,我们假定刚开始的时候所有牌的牌面向上。
现在对于每个块进行如下操作:
翻转某个块中的牌,并且与之相邻的其余八张牌也会被翻转。
XXX
XXX
XXX
如上矩阵所示,翻转中间那块时,这九块中的牌都会被翻转一次。
请输出在对矩阵中每一块进行如上操作以后,牌面向下的块的个数。
分析:暴力打表找规律即可,见代码
#include <bits/stdc++.h>
using namespace std;
//const int N = 1005;
int m,n;
//const int dx[] = {-1,-1,-1, 0, 0, 0, 1, 1, 1};
//const int dy[] = {-1, 0, 1,-1, 0, 1,-1, 0, 1};
//int a[N][N];
int main(void) {
int t;
cin>>t;
while(t--) {
scanf("%d%d",&n,&m);
// for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) a[i][j] = 0;
// for(int i=1;i<=n;++i)
// for(int j=1;j<=m;++j) {
// for(int k=0;k<9;++k) {
// int x = i+dx[k],y = j+dy[k];
// if(x>0&&x<=n&&y>0&&y<=m) {
// a[x][y]^=1;
//
// }
// }
// }
// int ans = 0;
// for(int i=1;i<=n;++i) {
// for(int j=1;j<=m;++j) {
// ans += a[i][j];
// }
// }
// cout<<ans<<endl;
if(n>m) swap(m,n);
if(n==1) {
if(m==1) puts("1");
else printf("%d\n",m+n-3);
}
else if(n==2) puts("0");
else {
printf("%lld\n",1ll*m*n-2ll*m-2ll*n+4);
}
}
return 0;
}
4/7 [编程题] 买房
在一条街上有n幢房子,标号从1到n,两个在标号上相差为1的房子视为相邻,这些房子中有k幢房子已有住户。
现你准备搬入这条街,你能搬入一幢房子的条件是这幢房子没有人住在里面,与此同时由于你非常热爱与邻居进行交流,故而你需要你所入住的房子两边上都有住户。
现要你求最小的可能符合要求的房子数,以及最大的可能符合要求的房子数。
Note: 就样例来说,#代表已有住户,-代表空位,这种情况(###—),没有满足条件的房子,为最小,故输出0
最大的情况为(#-#-#-),此种情况有二个位置满足条件,为最大,故输出2
分析:贪心
#include <bits/stdc++.h>
using namespace std;
int main(void) {
int T,n,k;
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&k);
if(n<=2||k<=1||k==n) { //没人,一个人,人满
puts("0 0");continue;
}
int minx = 0, maxx = 0;
if(n&1) { //n是奇数
int mid = (n+1)/2;
if(k<=mid) maxx = k-1;
else maxx = n/2-k+mid;
}
else {
int mid = n/2;
if(k<=mid) maxx = k-1;
else if(k==mid+1) maxx = mid-1;
else {
maxx = n-k;
}
}
printf("0 %d\n",maxx);
}
return 0;
}
5/7 [编程题]香槟塔
节日到啦,牛牛和妞妞邀请了好多客人来家里做客。
他们摆出了一座高高的香槟塔,牛牛负责听妞妞指挥,往香槟塔里倒香槟。
香槟塔有个很优雅的视觉效果就是如果这一层的香槟满了,就会从边缘处往下一层流去。
妞妞会发出两种指令,指令一是往第x层塔内倒体积为v的香槟,指令二是询问第k层塔香槟的体积为多少。
告诉你香槟塔每层香槟塔的初始容量,你能帮牛牛快速回答妞妞的询问吗?
分析:用线段树维护区间的剩余容量。询问第K层直接输出a[k]-query(k), 更新操作先二分出最后一个被填满的层,被填满的层区间都赋值为0(打lazy懒标记即可),没填满的那层单点更新。
#include <bits/stdc++.h>
using namespace std;
const int N = 200000+10;
typedef long long LL;
LL sum[N<<2];
int lazy[N<<2];
int a[N];
//线段树维护剩余的区间总容量
//更新操作只有两个,一个是区间全部赋值为0 用lazy即可
//另一个是单点更新
void push_up(int pos) {
sum[pos] = sum[pos<<1]+sum[pos<<1|1];
}
void push_down(int pos) {
if(lazy[pos]==-1) return;
sum[pos<<1] = sum[pos<<1|1] = 0;
lazy[pos<<1] = lazy[pos<<1|1] = 0;
lazy[pos] = -1;
}
void build(int left,int right,int pos) {
lazy[pos] = -1;
if(left==right) {
scanf("%d",&a[left]);
sum[pos] = a[left];
return;
}
int mid = (left+right)>>1;
build(left,mid,pos<<1);
build(mid+1,right,pos<<1|1);
push_up(pos);
}
LL query(int left,int right,int qL,int qR,int pos) {
if(qL>right||qR<left) return 0;
if(qL<=left&&right<=qR) return sum[pos];
int mid = (left+right)>>1;
push_down(pos);
return query(left,mid,qL,qR,pos<<1)+query(mid+1,right,qL,qR,pos<<1|1);
}
void update(int left,int right,int uL,int uR,int val,int pos) {
if(uL>right||uR<left) return;
if(uL<=left&&right<=uR) {
sum[pos] = val;
lazy[pos] = val;
return;
}
int mid = (left+right)>>1;
push_down(pos);
update(left,mid,uL,uR,val,pos<<1);
update(mid+1,right,uL,uR,val,pos<<1|1);
push_up(pos);
}
int main(void) {
int n,m,op,x,v;
scanf("%d%d",&n,&m);
build(1,n,1);
while(m--) {
scanf("%d",&op);
if(op==1) {
scanf("%d",&x);
printf("%lld\n",a[x]-query(1,n,x,x,1));
} else {
scanf("%d%d",&x,&v);
int L = x,R = n+1,M;
int xremain = query(1,n,x,x,1);
if(xremain>v) {
update(1,n,x,x,xremain-v,1);
continue;
}
while(R-L>1) {
M = (L+R)>>1;
if(query(1,n,x,M,1)<=v) L = M;
else R = M;
}
if(L==n) update(1,n,x,n,0,1);
else{
LL tmp = query(1,n,x,L,1);
update(1,n,x,L,0,1);
v -= tmp;
if(v>0) update(1,n,L+1,L+1,query(1,n,L+1,L+1,1)-v,1);
}
}
}
return 0;
}
6/7 [编程题] 社团主席选举
随着又一届学生的毕业,社团主席换届选举即将进行。
一共有n个投票者和m个候选人,小易知道每一个投票者的投票对象。但是,如果小易给某个投票者一些糖果,那么这个投票者就会改变他的意向,小易让他投给谁,他就会投给谁。
由于小易特别看好这些候选人中的某一个大神,这个人的编号是1,所以小易希望能尽自己的微薄之力让他当选主席,但是小易的糖果数量有限,所以请你帮他计算,最少需要花多少糖果让1号候选人当选。某个候选人可以当选的条件是他获得的票数比其他任何候选者都多。
分析:如果票数最高者是1号,则达到目的。然后就有两种方案。第一种从是票数最高的候选者那里抢走一个最便宜的人,一种是从所有不选1的人中抢走一个最便宜的人。dfs即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 3000+100;
int x[N],y[N],cnt[N],n,m;
bool vis[N];
long long ans;
int getMax() {
int id = 1;
for(int i=2;i<=m;++i) { //m个候选者
if(cnt[i]>=cnt[id]) id = i;
}
return id;
}
void getMinID(int id,int& xx,int & yy) {
xx = -1, yy = -1;
int totmin = 2000000000, idmin = 2000000000;
for(int i=2;i<=n;++i) { //n个投票者
if(vis[i]) continue;
if(x[i]==1) continue;
if(y[i]<totmin) xx = i, totmin = y[i];
if(x[i]==id) {
if(y[i]<idmin) yy = i,idmin = y[i];
}
}
}
void dfs(long long sum) {
int top1 = getMax();
if(top1==1) {
ans = min(ans,sum);
return;
}
int idtot,idtop;
getMinID(top1,idtot,idtop);
cnt[x[idtot]]--;
cnt[1]++;
vis[idtot] = true;
dfs(sum+y[idtot]);
vis[idtot] = false;
cnt[1]--;
cnt[x[idtot]]++;
if(idtop!=idtot) {
cnt[x[idtop]]--;
cnt[1]++;
vis[idtop] = true;
dfs(sum+y[idtop]);
vis[idtop] = false;
cnt[1]--;
cnt[x[idtop]]++;
}
}
int main(void) {
cin>>n>>m;
for(int i=1;i<=n;++i) {
scanf("%d%d",x+i,y+i);
cnt[x[i]]++;
}
ans = 200000000000000;
dfs(0ll);
cout<<ans<<endl;
return 0;
}
7/7 [编程题] 橡皮泥斑马
小易很喜欢斑马,因为它们身上黑白相间的花纹。
一天小易得到了一串橡皮泥,这串橡皮泥只有黑色和白色,小易想把这串橡皮泥重新拼凑一下,让这个橡皮泥串中最长的连续的黑白相间的子串最长,但是小易有强迫症,所以他可以对橡皮泥串进行以下的操作0次或多次:
把橡皮泥串从某个地方切割开,将两个得到的两个串同时翻转,再拼接在一起。
这个橡皮泥串可能太长了,所以小易没有办法计算最终可以得到的最长的连续的黑白相间的子串的长度,希望你能帮他计算出这个长度。
分析:两边各自翻转再合起来翻转,是循环左移(或右移)的O(n)做法。相当于可以循环移动。我们把两个原串拼接,然后直接dp即可。
dp[x]代表以str[x]结尾的最大交替串长度
dp[x] = (a[x]!=a[i-1)?dp[x-1]+1:1;
ans = max(ans,dp[i];
#include <bits/stdc++.h>
using namespace std;
const int N = 200000+100;
char str[N];
int main(void) {
scanf("%s",str);
int len = strlen(str);
for(int i=0;i<len;++i) str[i+len] = str[i];
str[len*2] = 0;
len = len+len;
int pre = 1;
int ans = 0;
for(int i=1;i<len;++i) {
if(str[i]!=str[i-1]) pre = pre+1;
else pre = 1;
ans = max(ans,pre);
}
cout<<ans<<endl;
return 0;
}
笔试加油!
2020.8.7 20:56