POJ 3495 Bitwise XOR of Arithmetic Progression 数论
2015-10-08 14:58
375 查看
题目链接:http://poj.org/problem?id=3495
题目大意:
求等差数列的异或和。
给定x,y,z,计算出首项为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变成了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)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
代码:
题目大意:
求等差数列的异或和。
给定x,y,z,计算出首项为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变成了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)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; }
相关文章推荐
- 1.m分解阶乘之和
- 2.几种递推数
- 3.欧拉函数
- 4.快速幂模m算法
- 5.扩展欧几里得&&中国剩余定理
- 6.数论_web
- POJ ACM 1001
- POJ ACM 1002
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- 编程之美2015初赛A
- 用单调栈解决最大连续矩形面积问题