51nod 1228 序列求和【伯努利数】【自然数幂的和】

2024-03-02 08:58

本文主要是介绍51nod 1228 序列求和【伯努利数】【自然数幂的和】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 题目链接:
  • 伯努利数来求
  • 递推式来求

题目链接:

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1228&judgeId=550328
就是求自然数幂的和

伯努利数来求

早就听说过伯努利数了,但是感觉太难了,一直没管,但是今天因为队友的一道题,突然推出一个递推式,貌似阔以用 O ( n 2 ) O(n^2) O(n2)解决。。。结果别人的测试数据有几千组,每组都是 O ( n 2 ) O(n^2) O(n2)的话就超时了,而伯努利数的这种方法是先 O ( n 2 ) O(n^2) O(n2)求出伯努利数,然后再用 O ( n ) O(n) O(n)求出每组测试数据,这样就不得超时了

伯努利数的递推式: ∑ i = 0 k C k + 1 i B i = 0 \sum_{i=0}^{k}C_{k+1}^iB_i=0 i=0kCk+1iBi=0每个 B k B_k Bk都用这个算一下,就是 O ( n 2 ) 了 O(n^2)了 O(n2)

然后计算答案用这个公式:
1 k + 1 ∑ i = 1 k + 1 C k + 1 i B k + 1 − i ( n + 1 ) i \frac{1}{k+1}\sum_{i=1}^{k+1}C^i_{k+1}B_{k+1-i}(n+1)^i k+11i=1k+1Ck+1iBk+1i(n+1)i

伯努利这个公式怎么来的我也不知道。。。希望有一天能够懂怎么来的

#include"bits/stdc++.h"
using namespace std;
const int maxn=2e3+5;
const long long MOD=1e9+7;
long long fac[maxn],inv[maxn];
long long N,K,T;
long long B[maxn];//伯努利数
long long ksm(long long a,long long b)
{long long res=1,base=a;while(b){if(b&1)res=(res*base)%MOD;base=(base*base)%MOD;b>>=1;}return res;
}
void Init()
{fac[0]=fac[1]=inv[0]=inv[1]=1;for(long long i=2;i<=2002;i++){fac[i]=(fac[i-1]*i)%MOD;inv[i]=(inv[i-1]*ksm(i,MOD-2))%MOD;}
}
long long C(int n,int m)
{if(m==0||n==m)return 1;long long res=(fac[n]*inv[m])%MOD;res=(res*inv[n-m])%MOD;return res;
}
void Bernoulli()//O(n^2)求伯努利数
{B[0]=1;long long sum=1;for(int i=1;i<=2001;i++){long long tp=0;for(int j=0;j<i;j++)tp=(tp+C(i+1,j)*B[j])%MOD;B[i]=((MOD-tp)*ksm(i+1,MOD-2))%MOD;}
}
long long f()//O(n)求答案
{long long p[maxn]={1};for(int i=1;i<=K+1;i++)p[i]=(p[i-1]*(N+1))%MOD;long long res=0;for(int i=1;i<=K+1;i++){long long tp=(C(K+1,i)*B[K+1-i])%MOD;tp=(tp*p[i])%MOD;res=(res+tp)%MOD;}res=(res*ksm(K+1,MOD-2))%MOD;return res;
}
int main()
{Init();Bernoulli();cin>>T;while(T--){cin>>N>>K;N%=MOD;//开始忘了加上这句话。。。。。cout<<f()<<endl;}
}

递推式来求

以平方和来举例:

二 项 式 展 开 : ( n + 1 ) 3 = C 3 0 1 0 n 3 + C 3 1 1 1 n 2 + C 3 2 1 2 n 1 + C 3 3 1 3 n 0 二项式展开:(n+1)^3=C_3^01^0n^3+C_3^11^1n^2+C_3^21^2n^1+C_3^31^3n^0 :(n+1)3=C3010n3+C3111n2+C3212n1+C3313n0
把第一项移到左边去,并且系数是1,就省略了
( n + 1 ) 3 − n 3 = C 3 1 1 1 n 2 + C 3 2 1 2 n 1 + C 3 3 1 3 n 0 (n+1)^3-n^3=C_3^11^1n^2+C_3^21^2n^1+C_3^31^3n^0 (n+1)3n3=C3111n2+C3212n1+C3313n0
然后就开始推
( n + 1 ) 3 − n 3 = C 3 1 1 1 n 2 + C 3 2 1 2 n 1 + C 3 3 1 3 n 0 (n+1)^3-n^3=C_3^11^1n^2+C_3^21^2n^1+C_3^31^3n^0 (n+1)3n3=C3111n2+C3212n1+C3313n0
( n ) 3 − ( n − 1 ) 3 = C 3 1 1 1 ( n − 1 ) 2 + C 3 2 1 2 ( n − 1 ) 1 + C 3 3 1 3 ( n − 1 ) 0 (n)^3-(n-1)^3=C_3^11^1(n-1)^2+C_3^21^2(n-1)^1+C_3^31^3(n-1)^0 (n)3(n1)3=C3111(n1)2+C3212(n1)1+C3313(n1)0
( n − 1 ) 3 − ( n − 2 ) 3 = C 3 1 1 1 ( n − 2 ) 2 + C 3 2 1 2 ( n − 2 ) 1 + C 3 3 1 3 ( n − 2 ) 0 (n-1)^3-(n-2)^3=C_3^11^1(n-2)^2+C_3^21^2(n-2)^1+C_3^31^3(n-2)^0 (n1)3(n2)3=C3111(n2)2+C3212(n2)1+C3313(n2)0
. . . ... ...
( 2 − 1 ) 3 − 1 3 = C 3 1 1 1 1 2 + C 3 2 1 2 1 1 + C 3 3 1 3 1 0 (2-1)^3-1^3=C_3^11^11^2+C_3^21^21^1+C_3^31^31^0 (21)313=C311112+C321211+C331310

然后把这 n n n个式子求和,左边一加一减一加一减就只剩下 ( n + 1 ) 3 − 1 3 (n+1)^3-1^3 (n+1)313,所以
( n + 1 ) 3 − 1 3 = C 3 1 1 1 ( 1 2 + 2 2 + . . . + n 2 ) + C 3 2 1 2 ( 1 1 + 2 1 + . . . + n 1 ) + C 3 3 1 3 ( 1 0 + 2 0 + . . . + n 0 ) (n+1)^3-1^3=C_3^11^1(1^2+2^2+...+n^2)+C_3^21^2(1^1+2^1+...+n^1)+C_3^31^3(1^0+2^0+...+n^0) (n+1)313=C3111(12+22+...+n2)+C3212(11+21+...+n1)+C3313(10+20+...+n0)
简写一哈就是这样:
A = C 3 1 1 1 I 2 + C 3 2 1 2 I 1 + C 3 3 1 3 I 0 A=C_3^11^1I_2+C_3^21^2I_1+C_3^31^3I_0 A=C3111I2+C3212I1+C3313I0
其中:
A = ( n + 1 ) 3 − 1 , 只 需 要 对 数 级 别 的 快 速 幂 计 算 一 哈 就 行 A=(n+1)^3-1,只需要对数级别的快速幂计算一哈就行 A=(n+1)31,
I 2 就 是 我 们 要 求 的 答 案 平 方 和 , I 1 是 一 次 方 和 , I 0 是 0 次 方 和 I_2就是我们要求的答案平方和,I_1是一次方和,I_0是0次方和 I2,I1,I00
所以递推一次差不多要 k k k次运算,然后要差不多 k k k次递推,所以是 k 2 k^2 k2的复杂度

/*递推版,每一计算是O(k^2),过不了*/
#include"bits/stdc++.h"
using namespace std;
const int maxn=2e3+5;
const int MOD=1e9+7;
long long dp[maxn];
long long fac[maxn],inv[maxn];
long long N,K,T;
long long C[maxn][maxn];
long long ksm(long long a,long long b)
{long long res=1,base=a;while(b){if(b&1)res=(res*base)%MOD;base=(base*base)%MOD;b>>=1;}return res;
}
void Init()
{fac[0]=fac[1]=inv[0]=inv[1]=1;for(long long i=2;i<=2000;i++){fac[i]=(fac[i-1]*i)%MOD;inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;}for(int i=0;i<=2000;i++){C[i][0]=C[i][i]=1;for(int j=1;j<i;j++){C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;}}}
long long f(int k)
{long long res=(ksm(N+1,k+1)-1+MOD)%MOD;long long tp=0;for(int i=2;i<=k+1;i++){tp+=(C[k+1][i]*dp[k+1-i])%MOD;tp%=MOD;}res=(res-tp+MOD)%MOD;res=(res*ksm(k+1,MOD-2))%MOD;return dp[k]=res;
}
int main()
{Init();cin>>T;while(T--){cin>>N>>K;dp[0]=N%MOD;for(int i=1;i<=K;i++)f(i);cout<<dp[K]<<endl;}
}

这篇关于51nod 1228 序列求和【伯努利数】【自然数幂的和】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/765578

相关文章

uva 10131 最长子序列

题意: 给大象的体重和智商,求体重按从大到小,智商从高到低的最长子序列,并输出路径。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vect

POJ1631最长单调递增子序列

最长单调递增子序列 import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.math.BigInteger;import java.util.StringTokenizer;publ

leetcode105 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3/ \9 20/ \15 7   class Solution {public TreeNode buildTree(int[] pr

day-50 求出最长好子序列 I

思路 二维dp,dp[i][h]表示nums[i] 结尾,且有不超过 h 个下标满足条件的最长好子序列的长度(0<=h<=k),二维数组dp初始值全为1 解题过程 状态转换方程: 1.nums[i]==nums[j],dp[i,h]=Math.max(dp[i,h],dp[j,h]+1) 2.nums[i]!=nums[j],dp[i,h]=Math.max(dp[i,h],dp[j,h-1

LeetCode:3177. 求出最长好子序列 II 哈希表+动态规划实现n*k时间复杂度

3177. 求出最长好子序列 II 题目链接 题目描述 给你一个整数数组 nums 和一个非负整数k 。如果一个整数序列 seq 满足在下标范围 [0, seq.length - 2] 中 最多只有 k 个下标i满足 seq[i] != seq[i + 1] ,那么我们称这个整数序列为好序列。请你返回 nums中好子序列的最长长度。 实例1: 输入:nums = [1,2,1,1,3],

用Python实现时间序列模型实战——Day 14: 向量自回归模型 (VAR) 与向量误差修正模型 (VECM)

一、学习内容 1. 向量自回归模型 (VAR) 的基本概念与应用 向量自回归模型 (VAR) 是多元时间序列分析中的一种模型,用于捕捉多个变量之间的相互依赖关系。与单变量自回归模型不同,VAR 模型将多个时间序列作为向量输入,同时对这些变量进行回归分析。 VAR 模型的一般形式为: 其中: ​ 是时间  的变量向量。 是常数向量。​ 是每个时间滞后的回归系数矩阵。​ 是误差项向量,假

1 模拟——67. 二进制求和

1 模拟 67. 二进制求和 给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 示例 1:输入:a = "11", b = "1"输出:"100"示例 2:输入:a = "1010", b = "1011"输出:"10101" 算法设计 可以从低位到高位(从后向前)计算,用一个变量carry记录进位,如果有字符没处理完或者有进位,则循环处理。两个字符串对

时间序列|change point detection

change point detection 被称为变点检测,其基本定义是在一个序列或过程中,当某个统计特性(分布类型、分布参数)在某时间点受系统性因素而非偶然因素影响发生变化,我们就称该时间点为变点。变点识别即利用统计量或统计方法或机器学习方法将该变点位置估计出来。 Change Point Detection的类型 online 指连续观察某一随机过程,监测到变点时停止检验,不运用到

Leetcode面试经典150题-128.最长连续序列-递归版本另解

之前写过一篇这个题的,但是可能代码比较复杂,这回来个简洁版的,这个是递归版本 可以看看之前的版本,两个版本面试用哪个都保过 解法都在代码里,不懂就留言或者私信 class Solution {/**对于之前的解法,我现在提供一共更优的解,但是这种可能会比较难懂一些(思想方面)代码其实是很简洁的,总体思想如下:不需要排序直接把所有数放入map,map的key是当前数字,value是当前数开始的

go json反序列化成指定类型

简介 简单的介绍一下使用go的json库,将json字符串反序列化成接口中指定的实现类 代码如下 package usejsontype ExamInterface interface {CheckRule(data any) bool}type IntStru struct {DefalutVal int `json:"defalut_val"`Max int `json: