网易后端2022.3.27题解和笔试情况
## 小红杀怪
枚举使用烈焰风暴的次数,然后可以O(1)算出需要使用火球术的次数。总复杂度 $O(n)$
枚举使用烈焰风暴的次数,然后可以O(1)算出需要使用火球术的次数。总复杂度 $O(n)$
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x, y, a, b, i;
cin >> x >> y >> a >> b;
int ma = 1e9;
for (i = 0; i <= 1e6; i++)
{
int c1 = 0, c2 = 0;
if ((x - i * b) > 0)
c1 = max(c1, (x - i * b) / a + ((x - i * b) % a != 0));
if ((y - i * b) > 0)
c2 = max(c2, (y - i * b) / a + ((y - i * b) % a != 0));
ma = min(ma, i + c1 + c2);
}
cout << ma;
} 这道题数据较小,可以直接暴力dfs。
后面我还想到了O(1)的贪心做法,根据 $x$ 和 $y$ 的大小关系进行分类讨论即可(这样1e9的数据也可以过):
后面我还想到了O(1)的贪心做法,根据 $x$ 和 $y$ 的大小关系进行分类讨论即可(这样1e9的数据也可以过):
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x, y, a, b, i;
cin >> a >> b >> x >> y;
if (y >= max(a, b))
cout << 1;
else if (y > x)
{
a = max(a, b);
cout << a / y + (a % y != 0);
}
else if (x > 2 * y)
{
cout << a / x + b / x + (a % x != 0) + (b % x != 0);
}
else
{
if (a > b) swap(a, b);
int cnt = a / y + (a % y != 0);
b -= y * cnt;
cout << b / x + (b % x != 0) + cnt;
}
} 小红标字母
线性dp即可,设 $dp[i]$ 为字符串前 $i$ 项可以获得的最大分数,然后转移。
#include <bits/stdc++.h>
using namespace std;
int dp[201010];
int main()
{
string s;
cin >> s;
int i;
for (i = 1; i < s.length(); i++)
{
dp[i + 1] = dp[i];
if (abs(s[i] - s[i - 1]) <= 1)
{
dp[i + 1] = max(dp[i + 1], dp[i - 1] + (s[i] - 'a' + 1) + (s[i - 1] - 'a' + 1));
}
}
cout << dp[s.length()];
} 小红的完全二叉树构造
题目要求任意两个相邻点乘积是偶数,也就是说不能有两个奇数相邻。我们发现完全二叉树是个二分图,所以让奇数和偶数间隔开,其中偶数放少的那一部分就行了。
还有一种简单的方法是:先打印所有根节点为偶数,再打印奇数就行了
#include <bits/stdc++.h>
using namespace std;
int out[101010];
int main()
{
int n, i;
cin >> n;
int temp = 1, c1 = 0, c2 = 0, jud = 1, nn = n;
while (temp <= n)
{
n -= temp;
if (jud & 1)
c1 += temp;
else
c2 += temp;
temp *= 2;
jud++;
}
if (jud & 1)
c1 += n;
else
c2 += n;
n = nn;
int ji = 1, ou = 2;
if (c1 < c2)
{
int temp = 2;
jud = 0;
for (i = 1; i <= n; i++)
{
if (temp == i)
jud = !jud, temp *= 2;
if (!jud)
{
if (ou > n)
{
cout << ji;
ji += 2;
}
else
{
cout << ou;
ou += 2;
}
}
else
{
if (ji > n)
{
cout << ou;
ou += 2;
}
else
{
cout << ji;
ji += 2;
}
}
cout << ' ';
}
}
else
{
int temp = 2;
jud = 0;
for (i = 1; i <= n; i++)
{
if (temp == i)
jud = !jud, temp *= 2;
if (jud)
{
if (ou > n)
{
cout << ji;
ji += 2;
}
else
{
cout << ou;
ou += 2;
}
}
else
{
if (ji > n)
{
cout << ou;
ou += 2;
}
else
{
cout << ji;
ji += 2;
}
}
cout << ' ';
}
}
}
小红闯沼泽地
其实就是个图论题,每个边权要么是1,要么是2,求最短路。所以可以通过dijkstra或者bfs求出来(bfs的话 需要把边长为2的边变成两个边长为1的边,有点麻烦,所以直接dijk解决了)
或者看成DP,类似于龙与地下城游戏:
#include <bits/stdc++.h>
using namespace std;
using PII = pair<int, int>;
const int dx[] = {1, 0, 0};
const int dy[] = {0, 1, -1};
const int N = 503;
struct Node
{
int x, y, w;
bool operator<(const Node &b) const { return w > b.w; }
};
int n, m;
int a[N][N];
priority_queue<Node> q;
int d[N][N];
bool vis[N][N];
int get(int x, int y)
{
return (x - 1) * m + y;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
cin >> a[i][j];
}
}
memset(d, 0x3f, sizeof(d));
d[1][1] = 0;
q.push({1, 1});
while (q.size())
{
int x = q.top().x, y = q.top().y;
q.pop();
if (vis[x][y])
continue;
vis[x][y] = true;
for (int i = 0; i < 3; ++i)
{
int tx = dx[i] + x, ty = dy[i] + y;
int w = (a[x][y] ^ a[tx][ty]) ? 2 : 1;
if (tx && ty && tx <= n && ty <= m)
{
if (d[tx][ty] > d[x][y] + w)
{
d[tx][ty] = d[x][y] + w;
q.push((Node){tx, ty, d[tx][ty]});
}
}
}
}
cout << d[n][m] << endl;
return 0;
} 
