美团笔试回忆

前言

  美团笔试是5道编程题,只做出来3.5道(当时赶时间上学校,只做了一个小时二十分钟就交了,也可能是题目有点难,毕竟字节笔试只做了半个小时就AC了。。。),前两题是水题,就不说了。这里说一下比较有意思的第三题------可能是运气好,在纸上画了十多分钟就出思路了。

题意

  令 b i = a i ⊕ 1 % i ⊕ 2 % i ⊕ . . . ⊕ n % i b_{i}=a_{i} \oplus 1\%i \oplus 2\%i \oplus ... \oplus n\%i bi=ai1%i2%i...n%i,要求 b 1 ⊕ b 2 ⊕ . . . ⊕ b n b_{1} \oplus b_{2} \oplus ... \oplus b_{n} b1b2...bn,其中 n < 1 0 5 n<10^{5} n<105 a i a_{i} ai题中会给出。

思路

  要求的结果无非是如下数字的异或。
   a 1 ⊕ a 2 ⊕ . . . ⊕ a n a_{1}\oplus a_{2}\oplus ...\oplus a_{n} a1a2...an
   1 % 1 ⊕ 2 % 1 ⊕ . . . ⊕ n % 1 1\%1\oplus 2\%1\oplus ...\oplus n\%1 1%12%1...n%1
   1 % 2 ⊕ 2 % 2 ⊕ . . . ⊕ n % 2 1\%2\oplus 2\%2\oplus ...\oplus n\%2 1%22%2...n%2
   . . . ... ...
   1 % n ⊕ 2 % n ⊕ . . . ⊕ n % n 1\%n\oplus 2\%n\oplus ...\oplus n\%n 1%n2%n...n%n

  化简后如下。
   a 1 ⊕ a 2 ⊕ . . . ⊕ a n a_{1}\oplus a_{2}\oplus ...\oplus a_{n} a1a2...an
   0 ⊕ 0 ⊕ . . . ⊕ 0 0\oplus 0\oplus ...\oplus 0 00...0
   1 ⊕ 2 ⊕ 0 ⊕ 1 ⊕ 2 ⊕ 0 ⊕ . . . ⊕ n % 2 1\oplus 2\oplus 0\oplus 1\oplus 2\oplus 0\oplus ...\oplus n\%2 120120...n%2
   1 ⊕ 2 ⊕ 3 ⊕ 0 ⊕ 1 ⊕ 2 ⊕ 3 ⊕ 0 ⊕ . . . ⊕ n % 3 1\oplus 2\oplus 3\oplus 0\oplus 1\oplus 2\oplus 3\oplus 0\oplus ...\oplus n\%3 12301230...n%3
   . . . ... ...
   1 ⊕ 2 ⊕ . . . ⊕ 0 1\oplus 2\oplus ...\oplus 0 12...0

  第一个式子直接累计异或即可,主要如何求下面的式子怎么求(对下面的式子从1开始编号)。
  可以看出下面的式子是有循环节的,我们不如将其分组。
  为了方便说明,假定 p r e i = 1 ⊕ 2 ⊕ . . . ⊕ i pre_{i}=1\oplus 2\oplus ... \oplus i prei=12...i
  比如对于1个式子,每组一个数0,最终结果为 0 n 0^{n} 0n(注意这个幂代表n个0异或)。
  对于第2个式子,每组2个数1和0,最终结果为 1 n 2 ⊕ p r e n % 2 1^{\frac{n}{2}}\oplus pre_{n\%2} 12npren%2
  一般地,对于第i个式子,每组n个数1,2,…,i-1,0,最终结果为 p r e i − 1 n i ⊕ p r e n % i pre_{i-1}^{\frac{n}{i}}\oplus pre_{n\%i} prei1inpren%i
   p r e i − 1 n i pre_{i-1}^{\frac{n}{i}} prei1in可以用快速幂求(注意不是常规的快速幂,要将乘法转化为异或)。

时间复杂度分析

  一共有n个式子,求每个式子需要快速幂,时间复杂度为 O ( log ⁡ ( n ) ) \mathcal{O}(\log(n)) O(log(n)),总的时间复杂度为 O ( n log ⁡ ( n ) ) \mathcal{O}(n\log(n)) O(nlog(n))

实现

#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N],pre[N];
int qpow(int a,int b){
    int res=0,rem=a;
    while(b){
        if(b&1) res^=rem;
        rem^=rem;
        b>>=1;
    }
    return res;
}
int main(){
    for(int i=1;i<N;i++){
        pre[i]=i^pre[i-1];
    }
    int n;cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int res=0;
    for(int i=1;i<=n;i++){
        res^=a[i];
    }
    for(int i=1;i<=n;i++){
        res^=qpow(pre[i-1],n/i)^pre[n%i];
    }
    cout<<res<<endl;
    return 0;
}

  之后发现可以不用快速幂,因为奇数个相同的数异或等于该数,偶数个相同的数异或等于0,所以只要判断 n i \frac{n}{i} in的奇偶就行了,时间复杂度为 O ( n ) \mathcal{O}(n) O(n)。不过那个数据量有意地让我联想到快速幂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值