您的位置:首页 > 其它

Xor Sum AtCoder - 2272 dp 转移方程

2018-01-26 10:36 465 查看
参考博客

题目链接

题解 建议翻译成英文看

You are given a positive integer N. Find the number of the pairs of integers u and v (0≦u,v≦N) such that there exist two non-negative integers a and b satisfying a xor b=u and a+b=v. Here, xor denotes the bitwise exclusive OR. Since it can be extremely large, compute the answer modulo 109+7.

Constraints

1≦N≦1018

Input

The input is given from Standard Input in the following format:

N

Output

Print the number of the possible pairs of integers u and v, modulo 109+7.

Sample Input 1

3

Sample Output 1

5

The five possible pairs of u and v are:

u=0,v=0 (Let a=0,b=0, then 0 xor 0=0, 0+0=0.)

u=0,v=2 (Let a=1,b=1, then 1 xor 1=0, 1+1=2.)

u=1,v=1 (Let a=1,b=0, then 1 xor 0=1, 1+0=1.)

u=2,v=2 (Let a=2,b=0, then 2 xor 0=2, 2+0=2.)

u=3,v=3 (Let a=3,b=0, then 3 xor 0=3, 3+0=3.)

Sample Input 2

1422

Sample Output 2

52277

Sample Input 3

1000000000000000000

Sample Output 3

787014179

题意:求有多少个数字对< u,v >满足 0≤u,v≤N 并且存在两个整数 a,b 使得a+b=u,a xor b=v

分析:我们发现只要 a,b 不超过 N,那么a xor b 也不会超过N,所以关键就是要保证 a+b 不超过 N,那么问题就转换成找到有多少组 a,b 使得 a+b≤N

首先这个题目要有上一步分析中的转换,接下来就是如何推递推方程,首先为了避免重复我们令a>=b

接着有两个初始解 F[0] F[1]

他们两个的a,b 分别是{0,0}和{(0,0),(1,0)}

接下来要接着往下递推就要考虑a+b<=n时二进制是如何由小到大转换过来的,首先从小到大转换时,假如直接转换二进制的的最右端的位数 来实现从小到大的转换这样递推式的右端项的个数会随着数的位数发生变化,因此形不成递推式,于是我们采用从要递推的数n的二分之一处寻找变化,我们计算只考虑{a,b}为为{1,0}的情况,我们知道整数在除2时,会发生向下取整的情况,因此一个数n 在由小数向大数递推的过程中总共有三种情况,分别是(n/2 + n/2 ),(n/2+1 + n/2),(n/2+1, n/2+1)这三种情况有时候加起来会小于等于n但是绝不能让他们出现大于n的情况,这就需要在递推的过程中一一对应,例如递推F[2]时,F[2] = F[1]+F[0]+F[0],

即 (0,0) (1,0) 对应F[1] 进行(n*2,n*2)的操作得到(0,0) (2,0),(0,0)对应第一个F[0]进行(n*2+1,n*2)的操作 得到 (1,0) ,(0,0)对应第二个F[0]进行(n*2+1,n*2+1)的操作得到(1,1), 最后F[2] = 4 ,即(0,0)(1,0)(1,1)(2,0)这四个(a,b)数对, 递推F[3]时 同样有

F[3] = F[1]+F[1]+F[0]
第一项F[1]进行(n*2,n*2)操作
(0,0)  (0,0)
(1,0)   (2,0)
第二项F[1]进行(n*2+1,n*2)操作
(0,0)   (1,0)
(1,0)    (3,0)
第三项F[0]进行(n*2+1,n*2+1)操作
(0,0)   (1,1)


其实在本质上看的二进制操作也比较好理解,要得到小于等于n的数,第一种操作是n/2即先将n>>1,然后n<<1,这样最后得到的数肯定不会超过n,第二种操作是((N-1)/2)*2+((N-1)/2),第三种操作是((N-2)/2)*2+1 + ((N-2)/2)*2+1 ,三种操作目的很明显,完成递推且数对数对(a,b)进行的操作不能使a+b出现大于n的情况,

所以下面的状态转移方程就好理解了



code:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const long long  mod = 1e9+7;
map<long long ,long long>dp;
#define bug cout<<88888888<<endl;
#define debug(x) cout << #x" = " << x << endl;
long long Dp(long long x)
{
if(dp[x])return dp[x];
else
{
return dp[x] = ((Dp(x/2)+Dp((x-1)/2)+Dp((x-2)/2)) )%mod;
}
}
int main()
{
dp[0] = 1;
dp[1] = 2;
long long n;
cin>>n;
cout<<Dp(n);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  异或 dp Atcoder 二进制