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 \}\)),得到的最大答案

状态转移:

\[\begin{align} &dp[i][j]=max\{ dp[i][j],dp[i-1][k]+b[i]\times a[i-1+j] \}\\ \\ &dp[i][j]=max\{ dp[i][j],dp[i-2][k]+b[i]\times a[i-1+j] \}\\ \\ &dp[i][j]=max\{ dp[i][j],dp[i-3][k]+b[i]\times a[i-1+j] \} \end{align} \]

  • 由于盖子能移动的距离不超过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\)、仅包含字符 AB 的事件字符串,你需要回答 \(Q\) 个查询 \((l_{\text{real}}, r_{\text{real}}, x)\)。每个查询要求计算二进制字符串 \(x\) 在经历了事件字符串区间 \([l_{\text{real}}, r_{\text{real}}]\) 内的事件后,会变成什么结果(其中 \(x\) 的最高位是最左边的位)。

事件 AB 的定义如下:

  • A: 将 \(x\) 中的所有0变为1,所有1变为0(同时进行)
  • B: 执行 \(x = x + 1\)(将 \(x\) 视为二进制表示的整数)。特别地,如果 \(x\) 全为1,则 \(x\) 会变成全0的二进制字符串

你需要在线回答每个查询。具体来说,对于第 \(i\) 次查询,实际询问的区间 \([l_{\text{real}}, r_{\text{real}}]\) 定义如下:

\[l_{\text{real}} = \min\left( (ans_{i-1} \oplus l) \% n + 1,\ (ans_{i-1} \oplus r) \% n + 1 \right) \]

\[r_{\text{real}} = \max\left( (ans_{i-1} \oplus l) \% n + 1,\ (ans_{i-1} \oplus r) \% n + 1 \right) \]

其中 \(\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\) 仅由字符 AB 组成。
接下来的 \(q\) 行,每行包含一个查询 \(l, r, x\) (\(1 \leq l \leq r \leq n\), \(1 \leq |x| \leq 50\)),其中 \(x\) 是一个仅包含 01 的二进制字符串。

输出描述

对于每个查询,输出二进制字符串 \(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\)次变换后的结果

\[\begin{align} &设F_{1\sim l-1}[x_{0}]=x\ ,\ F_{1\sim r}[x_{0}]=x_{1}\\ \\ &则F_{1\sim r}[x_{0}]=F_{l\sim r}[F_{1\sim l-1}[x_{0}]]=F_{l\sim r}[x]=x_{1} \end{align} \]

因此题目要求的\(F_{l\sim r}[x]\)即为\(x_{1}\)

\[x_{0}=F^{(-1)}_{1\sim l-1}[x] \]

由于变换为线性变换,很容易得到反函数并通过\(x\)解得\(x_{0}\)

\[x_{1}=F_{1\sim r}[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;
}

posted @ 2025-10-17 15:11  CUC-MenG  阅读(7)  评论(0)    收藏  举报