简要题意:
(T) 组数据,每组数据给定一个正整数 (n),求 所有将 (n) 分解为至少 (2) 个正整数之和的乘积之和。(拆分顺序不同也算方案不同)
例如 (n=3) 时,(3 = 1 + 1 + 1 = 1 + 2 = 2+1),所以答案为 (1 imes 1 imes 1 + 1 imes 2 + 2 imes 1 = 5). 答案对 (10^9+7) 取模。
数据范围:(T leq 10^3 , n leq 10^9).
很显然,考虑 (f_i) 表示 (i) 的答案。
貌似可以得到
[f_i = sum_{j=0}^{i-1} f_j (i-j)
]
枚举最后一个数为 (i-j) 的思路。
但是你会发现一个问题。因为 (f_i) 中不包含 (i=i) 的拆分;但转移中需要这个拆分。
于是换一换,令 (f_i) 表示 所有将 (n) 分解为至少 (1) 个正整数之和的乘积之和,上面的转移就是对的。
考虑 (f_i) 和很多东西有关,无法用矩阵优化。
我们试图让它只和 (f_{i-a})((a) 为常数)有关。
考虑:
[f_i - f_{i-1} = sum_{j=0}^{i-1} f_j(i-j) - sum_{j=0}^{i-2} f_j(i - 1 - j)
]
[= f_{i-1} + sum_{j=0}^{i-2} f_j
]
[= sum_{j=0}^{i-1} f_j
]
这不就是前缀和么。用 (g) 表示 (f) 的前缀和。易得:
[egin{cases}
f_i = f_{i-1} + g_{i-1} \
g_i = g_{i-1} + f_i = f_{i-1} + 2 * g_{i-1}\
end{cases}
]
考虑如何用矩阵维护它。易得:
[egin{vmatrix}1&1\1&2end{vmatrix} imes egin{vmatrix} f_{i-1} \ g_{i-1} end{vmatrix} = egin{vmatrix} f_i \ g_i end{vmatrix}
]
然后直接维护就完了。
另外需要注意的是边界,坑了我好久。
(f_0=1 , g_0 = 0),和定义不同,注意一下。
另外,答案为 (f_n - n). (-) 的时候可能会成负数,要处理一下,这个又坑了我好久。
时间复杂度:(mathcal{O}(T log n)).
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MOD=1e9+7;
inline int read(){char ch=getchar(); int f=1; while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
int x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}
inline void write(int x) {
if(x<0) {putchar('-');write(-x);return;}
if(x<10) {putchar(char(x%10+'0'));return;}
write(x/10);putchar(char(x%10+'0'));
}
struct martix {
int a[3][3];
inline void print(martix a) {
for(int i=1;i<=2;i++) {
for(int j=1;j<=2;j++) printf("%d ",a.a[i][j]);
puts("");
} puts("");
}
inline martix chengfa(martix a,martix b) {
martix ans; memset(ans.a,0ll,sizeof(ans.a));
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
for(int k=1;k<=2;k++)
ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j]%MOD)%MOD;
return ans;
}
inline martix pw(martix a,int x) {
martix ans; memset(ans.a,0ll,sizeof(ans.a));
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++) ans.a[i][j]=a.a[i][j];
x--;
while(x) {
// a.print(a); ans.print(ans);
if(x&1) ans=chengfa(ans,a);
a=chengfa(a,a); x>>=1;
} /*a.print(a); ans.print(ans);*/ return ans;
}
} ;
signed main() {
int T=read(),n; while(T--) {
n=read();
martix p;
p.a[1][1]=1ll; p.a[1][2]=1ll; p.a[2][1]=1ll; p.a[2][2]=2ll;
martix ans=p.pw(p,n);
printf("%lld
",(ans.a[1][2]-n+MOD)%MOD);
}
return 0;
}