zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
    
  • 相关阅读:
    lunix查询jdk安装路径
    (四)爬虫之动态网页
    (二)爬虫之数据提取
    图及其衍生算法(Graphs and graph algorithms)
    树及其衍生算法(Trees and tree algorithms)
    数据结构之链表(Linked list)
    查找与排序算法(Searching adn Sorting)
    数据结构之双端队列(Deque)
    数据结构之队列(Queue)
    多个git账号的SSH配置
  • 原文地址:https://www.cnblogs.com/bifanwen/p/14198846.html
Copyright © 2011-2022 走看看