SP6286 SUMMUL - Sum of products 題解
阿新 • • 發佈:2020-12-27
簡要題意:
\(T\) 組資料,每組資料給定一個正整數 \(n\),求 所有將 \(n\) 分解為至少 \(2\) 個正整數之和的乘積之和。(拆分順序不同也算方案不同)
例如 \(n=3\) 時,\(3 = 1 + 1 + 1 = 1 + 2 = 2+1\),所以答案為 \(1 \times 1 \times 1 + 1 \times 2 + 2 \times 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 \]這不就是字首和麼。用 \(g\) 表示 \(f\) 的字首和。易得:
\[\begin{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} \]考慮如何用矩陣維護它。易得:
\[\begin{vmatrix}1&1\\1&2\end{vmatrix} \times \begin{vmatrix} f_{i-1} \\ g_{i-1} \end{vmatrix} = \begin{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\n",(ans.a[1][2]-n+MOD)%MOD);
}
return 0;
}