POJ 3495 Bitwise XOR of Arithmetic Progression 数论

本文介绍了一种高效解决等差数列异或和问题的方法,通过位运算和数学归纳,优化了大数据场景下的计算过程。利用递归求解公式,实现了O(log^2n)的时间复杂度。

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

题目链接:http://poj.org/problem?id=3495

题目大意:
求等差数列的异或和。
给定 x y z ,计算出首项为x,公差为 z ,末项y且末项 +z>y 的等差数列每项的异或和。
多组测试数据, x,y,z232,xy

题解:
显然大数据时暴力计算会超时,那么我们就从位运算的性质下手解决这一问题:
异或操作中每一位互不干扰,所以我们可以分别计算出答案每一位的值。
那么第i位的值就为 (x2i+x+z2i+x+2z2i++x+nz2i)%2
a=zb=xc=2i ,那么就可以将问题转化为求 n1x=0ax+bc
将式子中的 ac bc 提取出来,
可得 n1x=0ax+bc=acn(n1)2+bcn+n1x=0(a%c)x+(b%c)c
acn(n1)2+bcn 可求,问题转化为了求 n1x=0(a%c)x+(b%c)c
它的值等价于求下面的图中的整点数。
这里写图片描述
所求区域为青色区域和棕绿色区域。
图中青色点为所求整点。
易知棕绿色区域与灰色区域无整点( b%cc<1,(a%c)x+(b%c)c(a%c)n+(b%c)c<1
所以所求区域可看做青色与灰色部分,
我们令O’为原点,y轴负方向为x’轴正方向,x轴负方向为y’轴正方向,定义新的坐标系。
那么直线 y=(a%c)x+(b%c)c 就变为了 y=cx+((an+b)%c)a%c
所以 n1x=0ax+bc=(a%c)n+(b%c)c1x=0cx+((an+b)%c)a%c
观察变化前后的式子,发现 a 变成了c b 变成了(an+b)%c c 变成了a%c,与GCD类似,可以递归求解,时间复杂度为 O(log2n)
递归可以到当 n==0 时截止,也可以到当 an+b<c 时截止,因为此时答案必定为 0
附上直线变化的证明:
直线的斜率显然变为原来的倒数,由a%cc变为 ca%c
直线的截距为图中蓝色线的长度,不难求出它的长度为
n+b%ca%c(a%c)n+(b%c)ca%cc=n+b%ca%cc(a%c)n+(b%c)ca%c
我们知道 pqp=qq%p
所以 c(a%c)n+(b%c)c=n+b%ca%c(an+b)%ca%c
所以截距为 (an+b)%ca%c

代码:

#include<stdio.h>
typedef unsigned int u;
u cal(u a,u b,u c,u n)
{
    u re=0;
    re+=(a/c)*n*(n-1)/2+(b/c)*n;
    b%=c;
    a%=c;
    if(a*n+b<c)
    {
        return re;
    }
    else
    {
        return re+cal(c,(a*n+b)%c,a,(a*n+b)/c);
    }
}
int main()
{
    u x,y,z;
    while(~scanf("%u%u%u",&x,&y,&z))
    {
        u ans=0;
        u n=(y-x)/z+1;
        for(int i=0;i<32;i++)
        {
            ans|=(cal(z,x,1u<<i,n)&1)<<i;
        }
        printf("%u\n",ans);
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值