*题解: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\),其所做贡献和为:

\[\sum_{k=0}^{2^{\lvert s \rvert - p_i}-1} f(pre_{p_i - 1} + g(k)) \]

看到 \(f\) 的递推式,不难想到可以将其写成矩阵形式:

\[\begin{bmatrix} f(i)\\ f(i - 1) \end{bmatrix}= \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix} \cdot \begin{bmatrix} f(i - 1)\\ f(i - 2) \end{bmatrix} \]

有了这个,已知 \(f(i),f(i - 1)\),就可以快速求出 \(f(i + k)\)

\(h(i)\) 表示长度为 \(i\) 后缀任意取的所有 \(\begin{bmatrix} f(j)\\ f(j - 1) \end{bmatrix}\) 之和,\(j\) 为某个后缀的二进制 \(1\) 的个数。考虑如何刻画后缀任意选的过程。可以看作是每次在当前后缀的开头加入 \(0\)\(1\),那么根据分配律,我们有:

\[\begin{aligned} h(i) &= h(i - 1) + \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix} \cdot h(i - 1)\\ &= \begin{bmatrix} 1 & 0\\ 0 & 1 \end{bmatrix} \cdot h(i - 1) + \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix} \cdot h(i - 1)\\ &= \begin{bmatrix} 1 + 1 & 1\\ 1 & 1 \end{bmatrix} \cdot h(i - 1) \end{aligned} \]

根据递推式,令 \(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}}\),同样利用分配律,结果即为

\[\begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}^{pre_{p_i - 1}} \cdot \begin{bmatrix} 2 & 1\\ 1 & 1 \end{bmatrix}^{\lvert s \rvert - p_i} \cdot \begin{bmatrix} 0\\ 1 \end{bmatrix} \]

预处理矩阵幂,对 \(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;
}
posted @ 2026-08-03 16:17  yutar  阅读(3)  评论(0)    收藏  举报