51Nod - 1013 - 3的幂的和(分治、快速幂)

题目链接
??大致看了一下,网上的题解大多数是用的逆元做的,今天受lyd蓝书的启发,发现用分治也可以做这个。
??首先,我们设\(F(n) = 3^0 + 3^1 + 3^2 + ... + 3^n\)。
??1.如果n为奇数,那么\(F(n) = (3^0 + 3^1 + 3^2 ... + 3^{\frac{n-1}{2}}) + (3^{\frac{n+1}{2}} + ... + 3^n)\)。
进一步可得:\(F(n) = (3^0 + 3^1 + 3^2 ... + 3^{\frac{n-1}{2}}) + 3^{\frac{n+1}{2}}\times(3^0 + 3^1 + 3^2 + ... + 3^{\frac{n-1}{2}}) = (1 + 3^{\frac{n+1}{2}}) \times F(\frac{n-1}{2})\)。
??2.如果n为偶数怎么办呢?那么我们发现好像不太好处理的样子,但是!我们可以从多项式里面排除一个数让项数变成奇数!就是这么狠(
我们令\(F(n) = (3^0 + 3^1 + 3^2 ... + 3^{\frac{n}{2}-1}) + (3^{\frac{n}{2}} + ... + 3^{n-1}) + 3^n\)然后和第1条的方法同理提出来\(3^{\frac{n}{2}}\)就可以得到\(F(n)= (1 + 3^{\frac{n}{2}}) \times F(\frac{n}{2}-1) + 3^n\)。
??3.最后我们来考虑一下递归的终点,设x为函数递归终点前传入的参数,如果x为0的话,显然\(F(0) = 1\)。如果x大于0,若x为奇数,那么\(\frac{x-1}{2}\)最小等于0(x取1)。
若x为偶数,那么\(\frac{x}{2}-1\)最小也为0(x取2)所以说我们的函数的递归终点就是\(F(0) = 1\)。
??4.关于时间复杂度。我们可以看到每次我们递归之后计算量就减少了一半,如果每次递归n都是奇数的话,我们每次用快速幂计算又要花\(\lg(n)\)的时间,所以时间复杂度最坏也是\(O(\lg^2(n))\)。

//https://www.cnblogs.com/shuitiangong/
#include<set>
#include<map>
#include<list>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define endl '\n'
#define rtl rt<<1
#define rtr rt<<1|1
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define maxx(a, b) (a > b ? a : b)
#define minn(a, b) (a < b ? a : b)
#define zero(a) memset(a, 0, sizeof(a))
#define INF(a) memset(a, 0x3f, sizeof(a))
#define IOS ios::sync_with_stdio(false)
#define _test printf("==================================================\n")
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<ll, ll> P2;
const double pi = acos(-1.0);
const double eps = 1e-7;
const ll MOD =  1000000007;
const int INF = 0x3f3f3f3f;
const int _NAN = -0x3f3f3f3f;
const double EULC = 0.5772156649015328;
const int NIL = -1;
template<typename T> void read(T &x){
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
const int maxn = 1e5+10;
int n;
ll solve2(int y) {
    ll ans = 1, res = 3;
    while(y) {
        if (y&1) ans = ans*res%MOD;
        res = res*res%MOD;
        y >>= 1;
    }
    return ans%MOD;
}
ll solve(int n) {
    if (!n) return 1;
    ll fac = 1;
    if (n&1) fac = fac*(1+solve2(n/2+1))%MOD*solve(n>>1)%MOD;
    //因为C语言默认除法是向下取整的,所以n为奇数的时候n/2+1和(n+1)/2结果相等,这里只是为了打着方便,n>>1同理
    else fac = fac*((solve2(n) + (1+solve2(n>>1))*solve(n/2-1)%MOD)%MOD)%MOD;
    return fac;
}
int main(void) {
    IOS;
    while(cin >> n)
        cout << solve(n) << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/shuitiangong/p/12535696.html

时间: 2024-11-13 08:57:16

51Nod - 1013 - 3的幂的和(分治、快速幂)的相关文章

求幂大法,矩阵快速幂,快速幂模板题--hdu4549

hdu-4549 求幂大法.矩阵快速幂.快速幂 题目 M斐波那契数列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 6217 Accepted Submission(s): 1902 Problem Description M斐波那契数列F[n]是一种整数数列,它的定义如下: F[0] = a F[1] = b F[n] = F[n-1] *

51Nod 1046 A^B Mod C(日常复习快速幂)

1046 A^B Mod C 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 给出3个正整数A B C,求A^B Mod C. 例如,3 5 8,3^5 Mod 8 = 3. Input 3个正整数A B C,中间用空格分隔.(1 <= A,B,C <= 10^9) Output 输出计算结果 Input示例 3 5 8 Output示例 3 题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!prob

快速幂算法(矩阵快速幂还不是很会。。日后会更新)

PS:转载,自己写的不如人家,怕误导.转载地址:http://www.cnblogs.com/CXCXCXC/p/4641812.html 首先,快速幂的目的就是做到快速求幂,假设我们要求a^b,按照朴素算法就是把a连乘b次,这样一来时间复杂度是O(b)也即是O(n)级别,快速幂能做到O(logn),快了好多好多.它的原理如下: 假设我们要求a^b,那么其实b是可以拆成二进制的,该二进制数第i位的权为2^(i-1),例如当b==11时   a^11=a^(2^0+2^1+2^3) 11的二进制是

快速幂计算(整数快速幂/矩阵快速幂)

库函数pow是用朴素算法对浮点型数据进行幂运算的,时间复杂度为o(n),计算比较大的数可能会超时和数据溢出: //*************快速幂计算**************************************** 朴素算法实现: ll get_pow(ll x, ll n)  //** (这里的n要求不小于0,如果n小于0则令n=-n,并且最终返回1.0/ans即可){    ll ans=1;    while(n--)    {        ans*=x%MAX;    

Luogu 3758 [TJOI2017]可乐(有向图邻接矩阵幂的意义 矩阵快速幂)

题目描述 加里敦星球的人们特别喜欢喝可乐.因而,他们的敌对星球研发出了一个可乐机器人,并且放在了加里敦星球的1号城市上.这个可乐机器人有三种行为: 停在原地,去下一个相邻的城市,自爆.它每一秒都会随机触发一种行为.现 在给加里敦星球城市图,在第0秒时可乐机器人在1号城市,问经过了t秒,可乐机器人的行为方案数是多少? 输入输出格式 输入格式: 第一行输入两个正整数况N,M,N表示城市个数,M表示道路个数.(1 <= N <=30,0 < M < 100) 接下来M行输入u,v,表示u

【总结】矩阵快速幂

在学习矩阵快速幂之前,首先我们需要分别了解快速幂和矩阵乘法 快速幂 快速幂要求解的是这样一类问题: 给你A,B,C,求A的B次方模C的余数 A,C<=10^9,B<=10^18 如果我们线性去求,时间复杂度是O(n)的,但题目中给出的B是很大的数,这样显然会超时,我们可以用快速幂来加速这个过程. 我们可以想像一下小学的时候我们如何计算2^16 2^16=4^8=16^4=256^2=65536 那如何计算2^18呢? 2^18=4^9=44^8=416^4=4256^2=465536=2621

矩阵快速幂 模板与简单讲解

模板 快速幂模板 1 void solve(matrix t,long long o) 2 { 3 matrix e; 4 5 memset(e.a,0,sizeof(e.a)); 6 7 for (int i = 0;i < d;i++) 8 e.a[i][i] = 1; 9 10 while (o) 11 { 12 if (o & 1) 13 { 14 e = mul(e,t); 15 } 16 17 o >>= 1; 18 19 t = mul(t,t); 20 } 21

骨牌覆盖 快速幂

http://www.cnblogs.com/easonliu/p/4419459.html 输入 第1行:1个整数N.表示棋盘长度.1≤N≤100,000,000 输出 第1行:1个整数,表示覆盖方案数 MOD 19999997 样例输入 62247088 样例输出 17748018 当N很小的时候,我们直接通过递推公式便可以计算.当N很大的时候,只要我们的电脑足够好,我们仍然可以直接通过递推公式来计算.但是我们学算法的,总是这样直接枚举不是显得很Low么,所以我们要用一个好的算法来加速(装X

快速幂 x

快速幂! 模板如下: 1 #include<iostream> 2 #include<cmath> 3 #include<cstdio> 4 5 using namespace std; 6 7 int b,p,k; 8 9 int fastpow(int a,int b) 10 { 11 int r=1; 12 int base=a; 13 while(b!=0) 14 { 15 if(b%2!=0)//奇次幂 16 r=r*base; 17 base=base*ba

POJ 1995 (快速幂)

这道题普通做法会发生溢出且会超时,应当用快速幂来求解. 快速幂讲解 1 #include <cstdio> 2 #include <cmath> 3 using namespace std; 4 int main(){ 5 int Z; 6 scanf("%d",&Z); 7 while(Z--){ 8 int M, H; 9 unsigned long long sum = 0; 10 scanf("%d%d",&M,&am