51nod 1984 题解

博客详细介绍了51nod 1984题目的解题思路,重点在于利用因数的性质和整除分块技术来优化算法,将复杂度降低到O(n)。通过枚举每个数的因数d,并统计d被异或的次数,结合整除分块快速求解1~x的异或和,从而得出最终答案。提供了一段未经优化的代码作为起点,并提示可以进一步优化以提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意简述

f(n)f(n)f(n)为n的所有因数异或起来的结果,求f(1)xorf(2)xorf(3)⋯xorf(n)f(1) xor f(2)xorf(3)\cdots xorf(n)f(1)xorf(2)xorf(3)xorf(n)的值。

数据

输入:4
输出:7

解释
f(1)=1
f(2)=1^2
f(3)=1^3
f(4)=1^2^4
4个异或起来是1^3^2^7=7

思路

多亏样例解释写成这样工整的表格形式才让我早一点看出来!我们换个角度想想,我们枚举1~n里每个数的因数,设为d,被异或了多少次。如果d被异或了奇数次,则异或到答案(ans^=d),否则答案不变。(为什么?因为两个相同的数异或一下就没了!)那么,d被算了多少次呢?因为每连续d个数就有一个d的倍数,所以总共被算了⌊nd⌋\lfloor\frac{n}{d}\rfloordn次。

没优化的代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;

void Calc(int x)
{
    int ans=0;
    for(int d=1;d<=x;d++)
    {
        if ((x/d)&1)
        {
            ans^=d;
        }
    }
    printf("%lld\n",ans);
}

main()
{
    int n;scanf("%lld",&n);
    Calc(n);
    return 0;
}


但这样仍然是O(n)O(n)O(n)的。。。因为我们还要从1~n枚举d

但我们发现n/d有很多是一样的,所以尻♂虑打整除分块。如如果我们能O(1)求1~x的异或和(设为XorSum),则l ~ r的异或和就是XorSum(r)XorSum(r)XorSum(r)^XorSum(l−1)XorSum(l-1)XorSum(l1),然后就珂以跑整除分块了。快速求1 ~x的异或和的方法珂以上网找博客看看或者自己打表找规律( 反正就是能求 )。然后这个题目就做出来了。
代码:

#include<bits/stdc++.h>
#define int long long//记得开long long
using namespace std;

int XorSum(int x)//求1~x的异或和
{
	//你会发现:1~x的异或和是4个一周期的
    int t=x&3;//相当于t=x%4
    if (t&1) return (t>>1)^1;//t&1相当于t%2==1
    else return (t>>1)^x;
}
int RangeSum(int l,int r)//求l~r的异或和
{
    return XorSum(r)^XorSum(l-1);
}
void Calc(int x)
{
    int ans=0;
    for(int l=1,r;l<=x;l=r+1)//整除分块
    {
        r=x/(x/l);
        if ((x/l)&1)//如果是奇数
        {
            ans^=RangeSum(l,r);//就异或到答案
        }
    }
    printf("%lld\n",ans);
}

main()
{
    int n;scanf("%lld",&n);
    Calc(n);
    return 0;
}
//这么浪只能C++11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值