牛客刷题 - 网易2018校招编程题(思维 & 贪心 & )
这套题的难受还是有的,不过有些题想想还是可以做的,只是有些题用暴力的方法感觉有点失望。
Q1:
解题思路:这个题很明显,一个只能产奇数,一个只能产偶数,倒着分奇偶跑一遍就行啦~
代码如下:
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
int main()
{
int n;
while(~scanf("%d",&n))
{
stack<int> s;
while(n)
{
if(n&1)
{
n >>= 1;
s.push(1);
}
else
{
n = (n-2)>>1;
s.push(2);
}
}
while(!s.empty())
{
printf("%d",s.top());
s.pop();
}
printf("\n");
}
return 0;
}
Q2:
解题思路:这题没说的,直接算就行了。
代码如下:
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
int main()
{
int n;
while (~scanf("%d",&n))
{
int re = 0;
int temp = n;
while (temp)
{
re = re*10 + temp%10;
temp /= 10;
}
printf("%d\n",re+n);
}
return 0;
}
Q3:
解题思路:也是过一遍就行了,没难度。
代码如下:
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
int main()
{
char str[55];
while (~scanf("%s",str))
{
char pre = str[0];
int length = 1;
int cnt = 1;
int l = strlen(str);
int sum = 0;
for (int i = 1 ; i < l ; i++)
{
if (str[i] != pre)
{
pre = str[i];
cnt++;
sum += length;
length = 1;
}
else
length++;
}
sum += length;
printf("%.2lf\n",(double)sum/cnt);
}
return 0;
}
Q4:
解题思路:这个题就有点意思了。用贪心的思想,首先尽量向深处走(使用dfs查看深度),然后就分两种情况:1.把所有步数用光也走不到底,那么答案就是步数。2.如果可以走到最深处,那么剩下的步数就每两步走一个格子(这一句是关键,举几个例子就能想通了)。
代码如下:
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
vector<int> edge[55];
int max_deep;
void dfs(int from, int fa, int deep)
{
max_deep = max(max_deep, deep);
for (int i = 0 ; i < edge[fa].size() ; i++)
{
if (edge[fa][i] == from)
continue;
dfs(fa, edge[fa][i], deep+1);
}
}
int main()
{
int n, l;
while(~scanf("%d %d",&n,&l))
{
for (int i = 0 ; i < n ; i++)
edge[i].clear();
max_deep = 0;
for (int i = 1 ; i < n ; i++)
{
int t;
scanf("%d",&t);
edge[i].push_back(t);
edge[t].push_back(i);
}
dfs(0, 0, 0);
//如果最深的一层走不完,那直接就有结果了
if (l <= max_deep)
printf("%d\n",l+1);
else
printf("%d\n",max_deep+1+min(n-1-max_deep, (l-max_deep)>>1));
}
return 0;
}
Q5:
解题思路:这个题也有点意思,需要想明白下面几点:1.不是2的倍数的数必须和4的倍数相邻。2.2的倍数的那些数,可以考虑为一个数,例如2 2 2 2其实和一个2是同样的效果,也必须和4相邻(如果不在边界的话)。
所以问题就简单了,统计2的倍数(不是4的倍数),4的倍数,其它奇数的数量,如果4的数量可以满足足够插在上面的数字中,则可以满足。下面代码更直观一些。
代码如下:
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
int n;
scanf("%d",&n);
int cnt1 = 0; //是4的倍数
int cnt2 = 0; //不是4的倍数
int cnt3 = 0; //这里还要考虑不是2的倍数的数,如果没有,也是Yes
for (int i = 1 ; i <= n ; i++)
{
int t;
scanf("%d",&t);
if (t%4 == 0)
cnt1++;
else if (t%2 == 0)
cnt2++;
else
cnt3++;
}
if (cnt1 >= cnt3+(cnt2!=0)-1 || cnt3 == 0)
puts("Yes");
else
puts("No");
}
return 0;
}
Q6:
好题啊!!!
解题思路:本以为是个什么dp的问题(因为dp不好,一碰见没思路的计数问题就想到dp)。结果后来看了解题思路,发现就是暴力题:枚举每一个位置的括号,尝试放在各个位置,这时候的LCS一定是length-1,因为只有我们枚举的这个字符位置变了,这个也是最大的LCS,因为我们就移动了一个字符。然后我们把枚举成功的字符串放进set里,结果就是set.size()-1
代码如下:
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <iostream>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
int main()
{
string str;
while (cin >> str)
{
set<string> s;
s.insert(str);
//取每个字符
for (int i = 0 ; i < str.size() ; i++)
{
string pre = str.substr(0, i) + str.substr(i+1);
//枚举每个位置
for (int pos = 0 ; pos < pre.size() ; pos++)
{
string new_string = pre.substr(0,pos) + str[i] + pre.substr(pos);
//判断是否合法
int num = 0;
for (int j = 0 ; j < new_string.size() ; j++)
{
if (new_string[j] == '(')
num++;
else
num--;
if (num < 0)
break;
}
if (num == 0)
s.insert(new_string);
}
}
cout << s.size()-1 << endl;
}
return 0;
}
Q7:
还是一个好题
解题思路:考虑dp,我们反向思考。先画个抽象的图,dp[i][j]表示小Q演奏到i,牛博士演奏到j,可以想到dp[i][j] == dp[j][i],我们假设有三个音符:
可以发现右半边没画,就是因为两边其实是一样的。
每个结点表示当前结点和下面最优的结点(即花费最小)的贡献之和。
再看看状态是怎么转移的:比如我们看dp[1][2]这个结点,下来要演奏的是3号音符。如果让小Q演奏,那么状态就到了dp[3][2]上,代价为dp[3][2]+abs(num[3]-num[1])。其它的结点也就同理了。
代码如下:
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
LL dp[2005][2005];
int v[2005];
int n;
LL dfs(int i,int j)
{
int ne = max(i, j) + 1;
//如果没有下一个音符
if (ne == n+1)
return 0;
if (dp[i][j] != -1)
return dp[i][j];
dp[i][j] = 1e6*2000+5;
dp[i][j] = min(dp[i][j], dfs(ne, j) + (i ? abs(v[ne] - v[i]) : 0));
dp[i][j] = min(dp[i][j], dfs(i, ne) + (j ? abs(v[ne] - v[j]) : 0));
dp[j][i] = dp[i][j];
return dp[i][j];
}
int main()
{
scanf("%d",&n);
for (int i = 1 ; i <= n ; i++)
scanf("%d",&v[i]);
CLR(dp, -1);
printf("%lld\n",dfs(0,0));
return 0;
}
Q8:
解题思路:枚举三个点(确定十字),然后统计在这个十字上的点的数量即可。
代码如下:
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
struct Dot
{
int x,y;
}dot[55];
bool is_line(int i, int j, int k)
{
int x1 = dot[i].x - dot[j].x;
int y1 = dot[i].y - dot[j].y;
int x2 = dot[k].x - dot[j].x;
int y2 = dot[k].y - dot[j].y;
return (x1*y2 - x2*y1) == 0;
}
int main()
{
int n;
scanf("%d",&n);
for (int i = 1 ; i <= n ; i++)
scanf("%d",&dot[i].x);
for (int i = 1 ; i <= n ; i++)
scanf("%d",&dot[i].y);
int ans = min(n, 3);
for (int i = 1 ; i <= n ; i++)
{
for (int j = 1 ; j <= n ; j++)
{
if (i == j)
continue;
for (int k = 1 ; k <= n ; k++)
{
if (j == k || i == k)
continue;
int num = 3;
for (int p = 1 ; p <= n ; p++)
{
if (p==i || p==j || p==k)
continue;
if (is_line(i,j,p))
num++;
else if ((dot[i].x-dot[j].x)*(dot[k].x-dot[p].x) + (dot[i].y-dot[j].y)*(dot[k].y-dot[p].y) == 0)
num++;
}
ans = max(ans, num);
}
}
}
printf("%d\n",ans);
return 0;
}