目录
[D. 漫步](#D. 漫步)
[E. 密藏](#E. 密藏)
[F. 回响](#F. 回响)
D. 漫步
x + z 中包含了所有 x 中为 1 的二进制位,也就是说 x 加上 z 后不能破坏 x 中本身二进制位为 1 的位,因此只要找到 x 的二进制位中第一个为 0 的位,让这一位为 1,赋值给 z 即可。
cnt 是实际位数,pos 是处于第几位,但 pos 是从 0 开始的,二进制表示中最低位是第 0 位。所以最高位实际上是 cnt - 1。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5, INF = 1e18;
int T, n, ans;
string s;
int fpow(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1)
res *= a;
a *= a;
b >>= 1;
}
return res;
}
signed main()
{
cin >> T;
while (T --)
{
int x;
cin >> x;
int cnt = 0, pos = 0;
int tx = x;
while (tx != 0)
tx >>= 1, cnt ++; // 计算 x 的二进制表示有多少位
while (x & 1)
x >>= 1, pos ++; // 找到第一个为 0 的二进制位
if (pos == cnt) // 因为 pos 是从下标 0 开始,所以这里两个相等就已经是超过了最高位了
{
cout << "-1" << '\n';
continue;
}
int z = fpow(2, pos);
cout << z << '\n';
}
return 0;
}
E. 密藏
凡是想到用贪心做的,都先想一想能不能 dp。
dp [ i ] [ 0 / 1 ] 表示到前 i 号点的最大收益,0 和 1 分别表示两个世界。dp 的无后效性是指对于前 i 个点的答案,与 i 之后的点无关。每一个 i 都是存的以第 i 号点为终点的最优解。
定义好 dp 之后就是枚举状态转移的所有情况。每一个点都可以由当前世界的前一个点或者另外一个世界的前一个点转移来,区别是后者要加判断条件。因为每个点都可能有两种转移来的方式,所以要取 max。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5, INF = 1e18;
int T, n, k, ans, a[N], b[N], dp[N][2];
string s;
signed main()
{
cin >> n >> k;
for (int i = 1; i <= n; i ++)
cin >> a[i];
for (int i = 1; i <= n; i ++)
cin >> b[i];
for (int i = 1; i <= n; i ++)
dp[i][0] = -1, dp[i][1] = -1;
dp[1][0] = a[1];
for (int i = 2; i <= n; i ++)
{
if (dp[i - 1][0] != -1)
{
dp[i][0] = dp[i - 1][0] + a[i];
if (dp[i - 1][0] - k >= 0)
dp[i][1] = dp[i - 1][0] - k + b[i];
}
if (dp[i - 1][1] != -1)
{
dp[i][1] = max(dp[i][1], dp[i - 1][1] + b[i]);
if (dp[i - 1][1] - k >= 0)
dp[i][0] = max(dp[i][0], dp[i - 1][1] - k + a[i]);
}
}
ans = max(dp[n][0], dp[n][1]);
cout << ans;
return 0;
}
F. 回响
先处理第一堆石子前面的格子,然后处理第一堆到最后一堆,最后处理最后一堆以及后面的所有。
对于夹在有石子的格子中间的空格,就是受到两端石子数的限制,因此看一下距离能否满足,只可长不可短,如果长还要看奇偶性能否满足加一减一微调。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5, INF = 1e18;
int T, n, cnt, ans[N], a[N], b[N], pos[N];
string s;
signed main()
{
cin >> n;
for (int i = 1; i <= n; i ++)
{
cin >> a[i];
if (a[i] != 0)
{
cnt ++;
b[cnt] = a[i];
pos[cnt] = i;
}
}
if (pos[1] != 1)
for (int i = 1; i < pos[1]; i ++)
ans[i] = b[1] + pos[1] - i;
for (int i = 1; i < cnt; i ++)
{
ans[pos[i]] = b[i];
int t1 = abs(b[i + 1] - b[i]), t2 = pos[i + 1] - pos[i];
if (t1 > t2)
{
cout << "-1";
return 0;
}
if ((t2 - t1) % 2 != 0)
{
cout << "-1";
return 0;
}
int cnt = 1;
for (int j = pos[i] + 1; j < pos[i + 1]; j ++)
{
if (cnt <= t1)
{
if (b[i] < b[i + 1])
ans[j] = b[i] + cnt;
else
ans[j] = b[i] - cnt;
cnt ++;
}
else
{
if (ans[j - 1] == b[i + 1])
ans[j] = ans[j - 1] - 1;
else
ans[j] = ans[j - 1] + 1;
}
}
}
ans[pos[cnt]] = b[cnt];
for (int i = pos[cnt] + 1; i <= n; i ++)
ans[i] = ans[i - 1] + 1;
for (int i = 1; i <= n; i ++)
cout << ans[i] << ' ';
return 0;
}