cychester

BZOJ 3329 - Xorequ - 数位DP, 矩乘

Solution

发现 $x \ xor \  2x = 3x$ 仅当 $x$ 的二进制中没有相邻的 $1$

对于第一个问题就可以进行数位DP 了。

但是对于第二个问题, 我们只能通过递推 打表 来算出答案了。

推公式 打表 可知, 这是一个斐波那契数列, $a_0 = 1, a_1 = 2, a_2 = 3$.... 

通过矩阵快速幂优化递推就可以过啦

 

Code

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rd read()
 5 #define ll long long
 6 using namespace std;
 7  
 8 const int mod = 1e9 + 7;
 9  
10 const int N = 70;
11  
12 int T, a[100];
13 ll sum[N][2], n;
14  
15 struct matrix {
16     ll s[4][4];
17     matrix operator * (const matrix &b) const {
18         matrix re;
19         memset(re.s, 0, sizeof(re.s));
20         for(int i = 1; i <= 2; ++i)
21             for(int k = 1; k <= 2; ++k)
22                 for(int j = 1; j <= 2; ++j)
23                     re.s[i][j] = (re.s[i][j] + s[i][k] * b.s[k][j]) % mod;
24         return re;
25     }
26 }ans, st;
27  
28 struct node {
29     int id;
30     ll in, out1, out2;
31 }b[1005];
32  
33 ll read() {
34     ll X = 0 , p = 1; char c = getchar();
35     for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1;
36     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
37     return X * p;
38 }
39  
40 ll dfs(int pos, int pre, int lim, int lead) {
41     if(!pos) return lead == 0;
42     if(!lim && !lead && sum[pos][pre] != -1)
43         return sum[pos][pre];
44     int up = lim ? a[pos] : 1;
45     ll tmp = 0;
46     for(int i = 0; i <= up; ++i) {
47         if(pre && i)
48             continue;
49         tmp += dfs(pos - 1, i, lim && a[pos] == i, lead && i == 0);
50     }
51     if(!lim && !lead)
52         sum[pos][pre] = tmp;
53     return tmp;
54 }
55  
56 ll work(ll x) {
57     int len = 0;
58     while(x) a[++len] = x % 2, x /= 2;
59     return dfs(len , 0, true, true);
60 }
61  
62 inline bool cmp1(const node &A, const node &B ) {
63     return A.in < B.in;
64 }
65  
66 inline bool cmp2(const node &A, const node &B) {
67     return A.id < B.id;
68 }
69  
70 void print(ll x) {
71     sort(b + 1, b + 1 + T, cmp1);
72     memset(sum, -1, sizeof(sum));
73     memset(st.s, 0, sizeof(st.s));
74     memset(ans.s, 0, sizeof(ans.s));
75     st.s[1][2] = st.s[2][1] = st.s[2][2] = 1;
76     ans.s[1][1] = 1;
77     ans.s[1][2] = 2;
78     printf("%lld\n", work(x));
79     for(; x; x >>= 1, st = st * st)
80         if(x & 1) ans = ans * st;
81     printf("%lld\n", (ans.s[1][1] % mod + mod) % mod);
82 }
83  
84 int main()
85 {
86     T = rd;
87     for(; T; T--) print(rd);
88 }
89 
View Code

 

posted on 2018-09-15 07:45  cychester  阅读(111)  评论(0编辑  收藏  举报

导航