题解 | #Poi 的新加法(Easy Version)#

Poi 的新加法(Easy Version)

https://www.nowcoder.com/practice/9f766daa7e4042a786633c341fe9d7e2

题目链接

Poi 的新加法(Easy Version)

题目描述

Poi 定义了一种新的加法运算 ,它只保留二进制加法中的进位部分。其形式化定义为: 其中 & 代表按位与运算,<< 1 代表左移一位(相当于乘以2)。

给定一个长度为 的序列 。现有 次查询,每次查询给定一个区间 ,要求计算将该运算 连续地作用于区间内元素的结果,即:

输入:

  • 第一行一个整数 ,表示测试用例数。
  • 每个测试用例:
    • 第一行两个整数 ,表示序列长度和查询次数。
    • 第二行 个整数,表示序列 的元素。
    • 接下来 行,每行两个整数 ,表示查询区间。

输出:

  • 对每次查询,输出一个整数作为结果。

解题思路

本题是此问题的“简单版本”,其数据范围相对较小,这提示我们可以使用一种直接的方法来解决。

问题的核心是理解并实现题目定义的运算 ,并将其依次应用在指定区间的元素上。 运算 不是一个标准的代数运算,我们无法直接判断它是否满足结合律等性质以进行预计算优化(例如使用前缀和或线段树)。

  • 结合律验证:
  • 显然,这两个表达式不相等,所以运算 不满足结合律

因此,我们不能改变运算的顺序,必须严格按照从左到右的顺序进行计算。 对于“简单版本”, 的规模(均不超过1000)允许我们对每次查询都进行一次暴力的线性扫描。

算法步骤如下:

  1. 对于每个查询 [l, r]
  2. 创建一个变量 current_result,并用区间的第一个元素 初始化它。注意,由于位运算中存在左移操作,结果可能会超出普通整型范围,因此最好使用长整型 (long long in C++, long in Java) 来存储。
  3. 从区间的第二个元素 开始,遍历到
  4. 在循环中,不断更新 current_resultcurrent_result = f(current_result, a_i),即 current_result = (current_result & a_i) << 1
  5. 循环结束后,current_result 就是本次查询的最终答案。

这种方法的单个查询时间复杂度为 ,总时间复杂度为 ,对于本题的数据范围是完全可以接受的。

代码

#include <iostream>
#include <vector>

using namespace std;

void solve() {
    int n, q;
    cin >> n >> q;
    vector<long long> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }

    for (int i = 0; i < q; ++i) {
        int l, r;
        cin >> l >> r;
        // 使用 long long 防止左移操作导致溢出
        long long current_result = a[l - 1];
        for (int j = l; j < r; ++j) {
            // 严格按顺序执行 f 运算
            current_result = (current_result & a[j]) << 1;
        }
        cout << current_result << endl;
    }
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        while (t-- > 0) {
            solve(sc);
        }
    }

    public static void solve(Scanner sc) {
        int n = sc.nextInt();
        int q = sc.nextInt();
        long[] a = new long[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextLong();
        }

        for (int i = 0; i < q; i++) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            // 使用 long 防止左移操作导致溢出
            long currentResult = a[l - 1];
            for (int j = l; j < r; j++) {
                // 严格按顺序执行 f 运算
                currentResult = (currentResult & a[j]) << 1;
            }
            System.out.println(currentResult);
        }
    }
}
def solve():
    # 读取 n 和 q
    n, q = map(int, input().split())
    # 读取数组 a
    a = list(map(int, input().split()))
    
    for _ in range(q):
        # 读取查询区间 l 和 r
        l, r = map(int, input().split())
        # Python 的整数类型自动处理大数,无需担心溢出
        current_result = a[l - 1]
        for i in range(l, r):
            # 严格按顺序执行 f 运算
            current_result = (current_result & a[i]) << 1
        print(current_result)

# 读取测试用例数
t = int(input())
for _ in range(t):
    solve()

算法及复杂度

  • 算法:暴力模拟、迭代计算
  • 时间复杂度:每个查询需要 的时间,总共 个查询,所以每个测试用例的总时间复杂度为 ,最坏情况下是
  • 空间复杂度:,主要用于存储输入的序列
全部评论

相关推荐

不愿透露姓名的神秘牛友
2025-12-17 16:48
今天九点半到公司,我跟往常一样先扫了眼电脑,屁活儿没有。寻思着没事干,就去蹲了个厕所,回来摸出手机刷了会儿。结果老板刚好路过,拍了我一下说上班别玩手机,我吓得赶紧揣兜里。也就过了四十分钟吧,我的直属领导把我叫到小隔间,上来就给我一句:“你玩手机这事儿把老板惹毛了,说白了,你可以重新找工作了,等下&nbsp;HR&nbsp;会来跟你谈。”&nbsp;我当时脑子直接宕机,一句话都没憋出来。后面&nbsp;HR&nbsp;找我谈话,直属领导也在旁边。HR&nbsp;说我这毛病不是一次两次了,属于屡教不改,不光上班玩手机,还用公司电脑看论文、弄学校的事儿。我当时人都傻了,上班摸鱼是不对,可我都是闲得发慌的时候才摸啊!而且玩手机这事儿,从来没人跟我说过后果这么严重,更没人告诉我在公司学个习也算犯错!连一次口头提醒都没有,哪儿来的屡教不改啊?更让我膈应的是,昨天部门刚开了会,说四个实习生里留一个转正,让大家好好表现。结果今天我就因为玩手机被开了。但搞笑的是,开会前直属领导就把我叫去小会议室,明明白白告诉我:“转正这事儿你就别想了,你的学历达不到我们部门要求,当初招你进来也没打算给你这个机会。”合着我没入贵厂的眼是吧?可我都已经被排除在转正名单外了,摸个鱼至于直接把我开了吗?真的太离谱了!
rush$0522:转正名单没进,大概率本来就没打算留你
摸鱼被leader发现了...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务