【备战秋招】每日一题:2023.03.26-腾讯实习-第四题-子数组异或和

为了更好的阅读体检,可以查看我的算法学习网
本题在线评测链接:P1125

题目内容

塔子哥是一位热爱数学和计算机科学的年轻人。他一直喜欢思考各种有趣的问题,并利用自己的知识和技能来解决它们。现在塔子哥有一个正整数数组 A A A ,他想玩一个游戏,找出数组中有多少个连续的子数组,满足以下条件: 子数组中的所有数字相乘的结果和相异或的结果相等。

每有一个满足条件的子数组即得一分,问塔子哥最多能得到多少分?

一个数组的子数组指数组中非空的一段连续数字。

输入描述

第一行一个正整数 n n n,代表给出数组长度

第二行 n n n 个空格分隔的正整数 A A A;

1 ⩽ n ⩽ 1 0 5 1 \leqslant n \leqslant 10^5 1n105

1 ⩽ A i ⩽ 1 0 9 1 \leqslant A_i \leqslant 10^9 1Ai109

输出描述

输出一个正整数代表答案

样例

输入

5
1 2 3 4 5

输出

5

思路

几个数字的乘积等于这几个数字的异或和,这要求这几个数字中只能由一个数字和若干偶数个1组成,按照这个想法用动态规划统计每一段连续1的贡献,并分别统计非1数字的贡献即可。

代码

c++

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5+10;
LL dp[N][2];
LL a[N];
LL cal(vector<int> t) {
	LL res = 0;
	for(int i = 1 ; i+1 < t.size() ; i ++) {
		if(t[i]) {
			for(int j = 0 ; j < t[i] ; j ++) {
				res += t[i] - j + 1 >> 1;
			}
		} else {
			res += dp[t[i-1]][0] * dp[t[i+1]][0];
			res += dp[t[i-1]][1] * dp[t[i+1]][1];
		}
	}
	return res;
}
int main()
{
	int n;
	cin >> n;
	for(int i = 1 ; i <= n ; i ++) cin >> a[i];
    dp[0][0] = 1;
	for (int i = 1; i <= n; i++) {
        dp[i][0] = dp[i-1][1] + 1;
        dp[i][1] = dp[i-1][0];
    }
	vector<int> tmp(1);
	for(int i = 1 ; i <= n ; i ++) {
	    if(a[i] == 1) {
	        int cnt = 0;
	        while(i <= n && a[i] == 1) {
	            i++, cnt++;
	        }
	        i--;
	        tmp.push_back(cnt);
	    } else {
	        tmp.push_back(0);
	    }
	}
    tmp.push_back(0);
	cout << cal(tmp) << endl;
}

java

import java.util.*;
public class Main {
    static long cal(int L, int R) {
        long[][] dp = new long[Math.max(L, R) + 1][2];
        dp[0][0] = 1;
        for (int i = 1; i < dp.length; i++) {
            dp[i][0] = dp[i-1][1] + 1;
            dp[i][1] = dp[i-1][0];
        }
        return dp[L][0] * dp[R][0] + dp[L][1] * dp[R][1];
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
        }
        List<Integer> tmp = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if(a[i] == 1) {
                int cnt = 0;
                while(i < n && a[i] == 1) {
                    i++;
                    cnt++;
                }
                i--;
                tmp.add(cnt);
            } else {
                tmp.add(0);
            }
        }
        long ans = 0;
        for (int i = 0; i < tmp.size(); i++) {
            if(tmp.get(i) == 0) {
                ans += cal(i==0?0:tmp.get(i-1), i+1==tmp.size()?0:tmp.get(i+1));
            } else {
                for (int j = 0; j < tmp.get(i); j++) {
                    ans += (tmp.get(i) - j + 1) / 2;
                }
            }
        }
        System.out.println(ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值