51nod 1984 题解

版权声明:博主是个蒟蒻,希望大家支持,如果要转发就转发吧,把我链接挂上即可。 https://blog.csdn.net/LightningUZ/article/details/88917775

题意简述

f ( n ) f(n) 为n的所有因数异或起来的结果,求 f ( 1 ) x o r f ( 2 ) x o r f ( 3 ) x o r f ( n ) f(1) xor f(2)xorf(3)\cdots 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的倍数,所以总共被算了 n d \lfloor\frac{n}{d}\rfloor 次。

没优化的代码:

#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) 的。。。因为我们还要从1~n枚举d

但我们发现n/d有很多是一样的,所以尻♂虑打整除分块。如如果我们能O(1)求1~x的异或和(设为XorSum),则l ~ r的异或和就是 X o r S u m ( r ) XorSum(r) ^ X o r S u m ( l 1 ) XorSum(l-1) ,然后就珂以跑整除分块了。快速求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

猜你喜欢

转载自blog.csdn.net/LightningUZ/article/details/88917775