bzoj3329 Xorequ
3329: Xorequ
Time Limit: 1 Sec Memory Limit: 256 MBSubmit: 1427 Solved: 601
[Submit][Status][Discuss]
Description
Input
第一行一个正整数,表示数据组数据 ,接下来T行
每行一个正整数N
Output
2*T行
第2*i-1行表示第i个数据中问题一的解,
第2*i行表示第i个数据中问题二的解,
Sample Input
1
1
1
Sample Output
1
2
2
HINT
x=1与x=2都是原方程的根,注意第一个问题的解
不要mod 10^9+7
1<=N<=10^18
1<=T<=1000
Source
分析:好题.
第一问考察对二进制数的运算的一些性质的掌握.
因为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; }