*题解:QOJ #10751. Fibonacci Sum
解析
考虑 \(n\) 中每个二进制 \(1\) 的位置 \(p_i\),假设我们要构造一个 \(x\in [0,n)\),则如果 \(x\) 在 \(p_i\) 位取 \(0\),则后面所有位可以 \(0,1\) 任意取。记 \(pre_i\) 表示高 \(i\) 位的 \(1\) 的个数,则对于所有由 \(n\) 的前 \(p_i - 1\) 位拼上 \(0\) 再拼上任意后缀的 \(x\),其所做贡献和为:
看到 \(f\) 的递推式,不难想到可以将其写成矩阵形式:
有了这个,已知 \(f(i),f(i - 1)\),就可以快速求出 \(f(i + k)\)。
设 \(h(i)\) 表示长度为 \(i\) 后缀任意取的所有 \(\begin{bmatrix} f(j)\\ f(j - 1) \end{bmatrix}\) 之和,\(j\) 为某个后缀的二进制 \(1\) 的个数。考虑如何刻画后缀任意选的过程。可以看作是每次在当前后缀的开头加入 \(0\) 或 \(1\),那么根据分配律,我们有:
根据递推式,令 \(f(-1) = 1\),则有 \(h(0) = \begin{bmatrix} 0\\ 1 \end{bmatrix}\)。综上可得 \(h(i)= \begin{bmatrix} 2 & 1\\ 1 & 1 \end{bmatrix}^{i} \cdot \begin{bmatrix} 0\\ 1 \end{bmatrix}\)。
这样我们就相当于知道了 \(\sum_{k=0}^{2^{\lvert s \rvert - p_i}-1} f(g(k))\),接下来就是要让每一项都变为 \(f(pre_{p_i - 1} + g(k))\),转化为矩阵就是每一项都乘上
\(\begin{bmatrix}
1 & 1\\
1 & 0
\end{bmatrix}^{pre_{p_i - 1}}\),同样利用分配律,结果即为
预处理矩阵幂,对 \(n\) 的每个二进制 \(1\) 位置求解即可。注意加上 \(f(g(n))\)。
时间复杂度 \(O(m^3\lvert s\rvert)\),\(m\) 为转移矩阵的阶。
代码
/*
*/
#include <bits/stdc++.h>
#define eps 0.0000000001
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef unsigned ui;
typedef pair<ll, ll> pii;
const int N = 10000000 + 5, M = 20, P = 450, mod = 1e9 + 7, mod2 = 1e9 + 7, b1 = 131;
struct Mtx{
int m[2][2];
int row = 2,col = 2;
Mtx(){
memset(m,0,sizeof(m));
}
Mtx(int r,int c) : row(r),col(c){
memset(m,0,sizeof(m));
}
Mtx operator * (Mtx b){
Mtx c(row,b.col);
for(int i=0;i<c.row;i++){
for(int k=0;k<col;k++){
for(int j=0;j<c.col;j++){
c.m[i][j] = (c.m[i][j] + 1ll * m[i][k] * b.m[k][j]) % mod;
}
}
}
return c;
}
void print(){
cout<<"_________________________\n";
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
cout<<m[i][j]<<" \n"[j==col - 1];
}
}
cout<<"_________________________\n";
}
};
Mtx h,b,c,mib[N];
int pre[N],f[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
string s;
cin>>s;
for(int i=0;i<s.size();i++){
pre[i + 1] = pre[i] + (s[i] == '1');
}
h.col = 1;
h.m[0][0] = 0,h.m[1][0] = 1;
b.m[0][1] = b.m[1][0] = b.m[1][1] = 1;
b.m[0][0] = 2;
mib[1] = b;
mib[0].m[0][0] = mib[0].m[1][1] = 1;
c.m[0][0] = 1;
c.m[0][1] = c.m[1][0] = 1;
f[0] = 0,f[1] = 1;
for(int i=2;i<=s.size();i++){
f[i] = (f[i - 1] + f[i - 2]) % mod;
mib[i] = b * mib[i - 1];
}
int res = f[pre[s.size()]];
Mtx nowc(2,2);
for(int i=0;i<2;i++){
nowc.m[i][i] = 1;
}
for(int i=1;i<=s.size();i++){
if(pre[i] != pre[i - 1]){
res = (res + (nowc * mib[s.size() - i] * h).m[0][0]) % mod;
nowc = nowc * c;
}
}
cout<<res;
return 0;
}

浙公网安备 33010602011771号