您的位置:首页 > 其它

bzoj3329 Xorequ

2018-02-23 15:28 204 查看

3329: Xorequ

Time Limit: 1 Sec Memory Limit: 256 MB
Submit: 1427 Solved: 601
[Submit][Status][Discuss]

Description



Input

第一行一个正整数,表示数据组数据 ,接下来T行
每行一个正整数N

Output

2*T行
第2*i-1行表示第i个数据中问题一的解,

第2*i行表示第i个数据中问题二的解,

Sample Input

1

1

Sample Output

1

2

HINT

x=1与x=2都是原方程的根,注意第一个问题的解
不要mod 10^9+7

1<=N<=10^18
1<=T<=1000

Source

By Wcmg

分析:好题.

   第一问考察对二进制数的运算的一些性质的掌握.

   因为a xor b = c等价于 a xor c = b,所以方程可以变形为x xor 2x = 3x. 

   既然涉及到xor运算,就要以二进制的视角去研究这些数. 2x可以看作x左移一位得到.

   观察发现3x = x + 2x,那么x xor 2x = x + 2x.

   xor又叫二进制运算中不进位的加法.不能进位,说明没有1在一起,而2x是由x左移得到的,所以可以得到结论:x不能有连续的1存在.可以用数位dp解决.

   第二问就考验找规律能力了. 这个数可能有10^18位,数位dp都处理不了了......也没有别的方法了,只能找规律. 找几个小点的n,很容易就能发现答案就是斐波那契数列的第n+2项,矩阵快速幂就能搞定.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
const ll mod = 1e9 + 7;
ll T,n,ans,num[1100],tot,f[1100][2];

struct node
{
ll x[3][3];
void clear()
{
memset(x,0,sizeof(x));
}
}a,b,c;

void operator *= (node &p,node &q)
{
c.clear();
for (int i = 1; i <= 2; i++)
for (int j = 1; j <= 2; j++)
for (int k = 1; k <= 2; k++)
c.x[i][j] = (c.x[i][j] + p.x[i][k] * q.x[k][j] % mod) % mod;
p = c;
}

ll dfs(ll len,ll if1,bool limit)
{
if (len == 0)
return 1;
if (!limit && ~f[len][if1])
return f[len][if1];
ll shangxian = (limit ? num[len] : 1),cnt = 0;
for (ll i = 0; i <= shangxian; i++)
{
if (i == 0 || if1 == 0)
cnt += dfs(len - 1,i,(limit && i == shangxian));
}
if (limit)
return cnt;
else
return f[len][if1] = cnt;
}

ll solve1()
{
tot = 0;
ll x = n;
while (x)
{
num[++tot] = x % 2;
x /= 2;
}
return dfs(tot,0,1);
}

void init()
{
tot = 0;
memset(num,0,sizeof(num));
memset(f,-1,sizeof(f));
ans = 0;
}

void qpow(ll c)
{
while (c)
{
if (c & 1)
a *= b;
b *= b;
c >>= 1;
}
}

void solve2()
{
a.clear();
b.clear();
a.x[1][1] = 1;
a.x[2][2] = 1;
b.x[1][1] = 1;
b.x[1][2] = 1;
b.x[2][1] = 1;
qpow(n + 1);
ans = a.x[1][1];
}

int main()
{
scanf("%lld",&T);
while (T--)
{
init();
scanf("%lld",&n);
printf("%lld\n",solve1() - 1);
solve2();
printf("%lld\n",ans);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: