2025牛客国庆集训派对day8 H K 个人题解
Box
dp #线性dp
题目来源: 牛客网
题目链接: Box
时间限制: C/C++/Rust/Pascal 1秒,其他语言2秒
空间限制: C/C++/Rust/Pascal 256 MB,其他语言512 MB
64位IO格式: %lld
题目描述
够了。没必要事事都扯上《原神》。《原神》并没有冒犯或伤害你。你为什么总是无脑抹黑它?米哈游通过游戏努力推广中国文化,而你只会坐在键盘前指责一家有良心的公司。像你这样的人正在毁掉中国游戏的未来。
现在,旅行者手中有 \(n\) 个盒子,其中一些盒子的盖子可以向左或向右最多移动一个位置。如果第 \(i\) 个盒子被盖子覆盖,你能获得 \(a_i\) 分数(用多个盖子覆盖它仍然只能获得 \(a_i\) 分数)。请在移动若干(可能为零)个盖子后,确定通过用盖子覆盖盒子所能获得的最大游戏总分。
输入描述
第一行包含一个整数 \(n\) (\(1 \leq n \leq 10^6\)),表示盒子的数量。
第二行包含 \(n\) 个整数,其中第 \(i\) 个整数 \(a_i\) (\(0 \leq a_i \leq 10^9\)) 表示第 \(i\) 个盒子的价值。
第三行包含 \(n\) 个整数,其中第 \(i\) 个整数 \(b_i\) (\(0 \leq b_i \leq 1\)) 表示第 \(i\) 个盒子是否有盖子。\(b_i = 0\) 表示该盒子上没有盖子。
输出描述
一个整数,表示答案。
思路
本题快修梆子井地道队赛时15分钟拿下一血,我们队直到比赛结束都没有找到正确的思路。
本题并不是什么\(priority\_queue\)或者贪心,就是纯粹的\(dp\)
状态表示:
\(dp[i][j]\)表示第\(1\sim i\)个盒子,第\(i\)个盖子放在第\(i-1+j\)个位置(\(j\in\{ 0,1,2 \}\)),得到的最大答案
状态转移:
- 由于盖子能移动的距离不超过3,因此能够转移到当前状态的前驱状态就只有3个,再往前就重复更新了
- 位置\(i\)的盖子放在\(i-1+j\)上,则位置\(i-t\)的盖子放的位置需要小于\(i-1+j\),因此对于不同的\(i-t\),需要用不等式限制\(k\)的范围
代码
#include<iostream>
#include<vector>
#include<unordered_map>
#include<map>
#include<unordered_set>
#include<set>
#include<algorithm>
#include<queue>
using namespace std;
const double eps = 1e-6;
#define ll long long
#define int ll
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define see(stl) for(auto&ele:stl)cout<<ele<<" ";cout<<'\n';
#pragma GCC optimize(3, "Ofast", "inline")
const int N = 1e6 + 5;
int a[N], b[N], dp[N][3];
void chmax(int& x, int y) { x = max(x, y); }
void solve() {
int n;cin >> n;
rep(i, 1, n)cin >> a[i];
rep(i, 1, n)cin >> b[i];
rep(i, 1, n) {
rep(j, 0, 2) {
rep(k, 0, 2) {
if (i - 1 + j >= 1 && k <= j)chmax(dp[i][j], dp[i - 1][k] + b[i] * a[i - 1 + j]);
if (i - 1 + j >= 1 && k <= j + 1 && i - 2 >= 0)chmax(dp[i][j], dp[i - 2][k] + b[i] * a[i - 1 + j]);
if (i - 3 >= 0)chmax(dp[i][j], dp[i - 3][k] + b[i] * a[i - 1 + j]);
}
}
}
int ans = 0;
rep(j, 0, 2)chmax(ans, dp[n][j]);
cout << ans << '\n';
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
//cin >> t;
while (t--)solve();
return 0;
}
0 and 1 in BIT
位运算 #数学 #前缀和
题目来源: 牛客网
题目链接: https://ac.nowcoder.com/acm/contest/117511/H
时间限制: C/C++/Rust/Pascal 2秒,其他语言4秒
空间限制: C/C++/Rust/Pascal 256 MB,其他语言512 MB
64位IO格式: %lld
题目描述
在二进制和BIT(二进制索引树)中,存在大量的0和1。
在BIT中,0和1的定义有时是模糊的——0有时会变成1,反之亦然。
现在,给定一个长度为 \(n\)、仅包含字符 A 和 B 的事件字符串,你需要回答 \(Q\) 个查询 \((l_{\text{real}}, r_{\text{real}}, x)\)。每个查询要求计算二进制字符串 \(x\) 在经历了事件字符串区间 \([l_{\text{real}}, r_{\text{real}}]\) 内的事件后,会变成什么结果(其中 \(x\) 的最高位是最左边的位)。
事件 A 和 B 的定义如下:
A: 将 \(x\) 中的所有0变为1,所有1变为0(同时进行)B: 执行 \(x = x + 1\)(将 \(x\) 视为二进制表示的整数)。特别地,如果 \(x\) 全为1,则 \(x\) 会变成全0的二进制字符串
你需要在线回答每个查询。具体来说,对于第 \(i\) 次查询,实际询问的区间 \([l_{\text{real}}, r_{\text{real}}]\) 定义如下:
其中 \(\oplus\) 表示按位异或运算,\(ans_{i-1}\) 是第 \(i-1\) 次查询的答案(被视为二进制表示的整数),且初始值 \(ans_0 = 0\)。
输入描述
第一行包含两个整数 \(n\) (\(3 \leq n \leq 2 \times 10^5\)) 和 \(q\) (\(1 \leq q \leq 2 \times 10^5\)),分别表示事件字符串的长度和查询次数。
第二行包含事件字符串 \(S\) (\(|S| = n\)),且 \(S\) 仅由字符 A 和 B 组成。
接下来的 \(q\) 行,每行包含一个查询 \(l, r, x\) (\(1 \leq l \leq r \leq n\), \(1 \leq |x| \leq 50\)),其中 \(x\) 是一个仅包含 0 和 1 的二进制字符串。
输出描述
对于每个查询,输出二进制字符串 \(x\) 在经历事件区间 \([l, r]\) 后的结果。
思路
本题最关键的思路在于,将取反操作视作\(2^{51}-1\)全一串与\(x\)相减
对于一次操作,我们可以视作\(x\to a(2^{51}-1)+bx+c\)
题干需要令\(x\)经过\(l\sim r\)次变换后的结果,可以通过类似前缀的思想来构造:
记三元组\(f(i)=\{ a[i],b[i],c[i] \}\)为\(1\sim i\)所有操作后的三个系数
记变换\(F_{1\sim i}[x]=a[i]\cdot(2^{51}-1)+b[i]\cdot x+c[i]\),表示令\(x\)经过\(1\sim i\)次变换后的结果
因此题目要求的\(F_{l\sim r}[x]\)即为\(x_{1}\)
由于变换为线性变换,很容易得到反函数并通过\(x\)解得\(x_{0}\)
代入变换即可得到最终答案
如何预处理三元组\(f(i)\)?
- 操作A:
- \(a[i]=1-a[i-1]\)
- \(b[i]=-b[i-1]\)
- \(c[i]=-c[i-1]\)
- 操作B:
- \(a[i]=a[i-1]\)
- \(b[i]=b[i-1]\)
- \(c[i]=c[i-1]+1\)
最后要注意输入输出时的强制在线机制
复杂度\(o(n+100q)\)
代码
#include<iostream>
#include<vector>
#include<unordered_map>
#include<map>
#include<unordered_set>
#include<set>
#include<algorithm>
#include<queue>
using namespace std;
const double eps = 1e-6;
#define ll long long
#define int ll
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define see(stl) for(auto&ele:stl)cout<<ele<<" ";cout<<'\n';
#pragma GCC optimize(3, "Ofast", "inline")
const int N = 2e5 + 5;
int a[N], b[N], c[N];
void solve() {
int n, q;cin >> n >> q;
string s;cin >> s;
b[0] = 1;
rep(i, 1, n) {
if (s[i - 1] == 'A')a[i] = 1 - a[i - 1], b[i] = -b[i - 1], c[i] = -c[i - 1];
else a[i] = a[i - 1], b[i] = b[i - 1], c[i] = c[i - 1] + 1;
}
int ans = 0;
rep(i, 1, q) {
int l, r;string ss;
cin >> l >> r >> ss;
int l1 = l, r1 = r;
l = min((ans ^ l1) % n + 1, (ans ^ r1) % n + 1);
r = max((ans ^ l1) % n + 1, (ans ^ r1) % n + 1);
//cout << "l,r:" << l << " " << r << '\n';
int x = 0;
rep(pos, 0, ss.length() - 1) {
x += (ss[ss.length() - 1 - pos] - '0') * (1ll << pos);
}
int x0 = b[l - 1] * (x - c[l - 1] - a[l - 1] * ((1ll << 51) - 1));
int x1 = a[r] * ((1ll << 51) - 1) + b[r] * x0 + c[r];
per(pos, ss.length() - 1, 0) {
cout << ((x1 >> pos) & 1);
}
ans = x1 & ((1ll << ss.length()) - 1);
cout << '\n';
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
//cin >> t;
while (t--)solve();
return 0;
}

浙公网安备 33010602011771号