您的位置:首页 > 其它

POJ 3495 Bitwise XOR of Arithmetic Progression 数论

2015-10-08 14:58 375 查看
题目链接:http://poj.org/problem?id=3495

题目大意:

求等差数列的异或和。

给定xyz,计算出首项为x,公差为z,末项≤y且末项+z>y的等差数列每项的异或和。

多组测试数据,x,y,z≤232,x≤y

题解:

显然大数据时暴力计算会超时,那么我们就从位运算的性质下手解决这一问题:

异或操作中每一位互不干扰,所以我们可以分别计算出答案每一位的值。

那么第i位的值就为(⌊x2i⌋+⌊x+z2i⌋+⌊x+2z2i⌋+……+⌊x+nz2i⌋)%2

a=z,b=x,c=2i,那么就可以将问题转化为求∑n−1x=0⌊ax+bc⌋

将式子中的⌊ac⌋⌊bc⌋提取出来,

可得∑n−1x=0⌊ax+bc⌋=⌊ac⌋∗n∗(n−1)2+⌊bc⌋∗n+∑n−1x=0⌊(a%c)x+(b%c)c⌋

⌊ac⌋∗n∗(n−1)2+⌊bc⌋∗n可求,问题转化为了求∑n−1x=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⌋

所以∑n−1x=0⌊ax+bc⌋=∑⌊(a%c)n+(b%c)c⌋−1x=0⌊cx+((an+b)%c)a%c⌋

观察变化前后的式子,发现a变成了cb变成了(an+b)%cc变成了a%c,与GCD类似,可以递归求解,时间复杂度为O(log2n)

递归可以到当n==0时截止,也可以到当an+b<c时截止,因为此时答案必定为0

附上直线变化的证明:

直线的斜率显然变为原来的倒数,由a%cc变为ca%c

直线的截距为图中蓝色线的长度,不难求出它的长度为

n+b%ca%c−⌊(a%c)n+(b%c)c⌋a%cc=n+b%ca%c−c⌊(a%c)n+(b%c)c⌋a%c

我们知道p⌊qp⌋=q−q%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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  POJ 数论