SP6286 SUMMUL

CSDN同步

原题链接

简要题意:

(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;
}


原文地址:https://www.cnblogs.com/bifanwen/p/14198846.html