[51nod1228][伯努利数][自然数k次幂和]序列求和
来源:互联网 发布:阿里云 谷歌api 编辑:程序博客网 时间:2024/06/07 22:01
题意
给定n,k,求
因为绍一模拟考的20分部分分,所以来学一发伯努利数
首先暴力求这个式子是要nlogk的,然而n是10^18……
然后了解到一个叫伯努利数的东西,这个k^2次预处理后O(k)求出解
伯努利数是一个乱七八糟的有理数数列,
定义
根据关系式
这样就可以O(k^2)预处理出伯努利数
因为又知道一个神奇的公式
那么就可以O(k)求出自然数k次幂和啦
学习自http://blog.csdn.net/acdreamers/article/details/38929067
#include <cstdio>#include <iostream>#include <algorithm>#define N 2010#define p 1000000007using namespace std;typedef long long ll;int t;ll n,k;ll inv[N],fac[N],invf[N],B[N];inline ll C(ll x,ll y){ return fac[x]*invf[y]%p*invf[x-y]%p;}inline void reaD(int &x){ char c=getchar();x=0; for(;c>57||c<48;c=getchar());for(;c>=48&&c<=57;x=x*10+c-48,c=getchar());}inline void reaD(ll &x){ char c=getchar();x=0; for(;c>57||c<48;c=getchar());for(;c>=48&&c<=57;x=x*10+c-48,c=getchar());}ll pow_(ll x,ll y){ x%=p; ll r=1; while(y){ if(y&1) r=r*x%p; x=x*x%p; y>>=1; } return r;}int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); invf[0]=inv[0]=inv[1]=fac[0]=fac[1]=1; for(ll i=1;i<=2005;i++) fac[i]=fac[i-1]*i%p; for(int i=2;i<=2005;i++) inv[i]=(p-p/i)*inv[p%i]%p; for(int i=1;i<=2005;i++) invf[i]=invf[i-1]*inv[i]%p; B[0]=1; for(int i=1;i<=2001;i++){ B[i]=0; for(int j=0;j<i;j++) B[i]=(B[i]+C(i+1,j)*B[j])%p; B[i]=((B[i]*-inv[i+1])%p+p)%p; } reaD(t); while(t--){ reaD(n); reaD(k); ll Ans=0; for(int i=1;i<=k+1;i++) Ans=(Ans+C(k+1,i)*B[k+1-i]%p*pow_(n+1,i))%p; Ans=Ans*inv[k+1]%p; printf("%lld\n",Ans); } return 0;}
查了下维基百科
伯努利数有两类,两类伯努利数的区别在于
第一类伯努利数,由美国国家标准技术研究所 (NIST)制定,在这标准下
第二类伯努利数,又被称为是“原始的白努利数“,在这标准下
上面的求自然数k次幂和是根据第一类伯努利数得出,可以看出这个做法得到的多项式是关于(n+1)的,那么在某些题目中,要求多项式关于n,这时候就需要用第二类伯努利数。
第二类伯努利数求自然数k次幂和:
很神奇啊
#include <cstdio>#include <iostream>#include <algorithm>#define N 2010#define p 1000000007using namespace std;typedef long long ll;int t;ll n,k;ll inv[N],fac[N],invf[N],B[N];inline ll C(ll x,ll y){ return fac[x]*invf[y]%p*invf[x-y]%p;}inline void reaD(int &x){ char c=getchar();x=0; for(;c>57||c<48;c=getchar());for(;c>=48&&c<=57;x=x*10+c-48,c=getchar());}inline void reaD(ll &x){ char c=getchar();x=0; for(;c>57||c<48;c=getchar());for(;c>=48&&c<=57;x=x*10+c-48,c=getchar());}ll pow_(ll x,ll y){ x%=p; ll r=1; while(y){ if(y&1) r=r*x%p; x=x*x%p; y>>=1; } return r;}int main(){ invf[0]=inv[0]=inv[1]=fac[0]=fac[1]=1; for(ll i=1;i<=2005;i++) fac[i]=fac[i-1]*i%p; for(int i=2;i<=2005;i++) inv[i]=(p-p/i)*inv[p%i]%p; for(int i=1;i<=2005;i++) invf[i]=invf[i-1]*inv[i]%p; B[0]=1; for(int i=1;i<=2001;i++){ B[i]=0; for(int j=0;j<i;j++) B[i]=(B[i]+C(i+1,j)*B[j])%p; B[i]=((B[i]*-inv[i+1])%p+p)%p; } B[1]=(p-B[1])%p; reaD(t); while(t--){ reaD(n); reaD(k); ll Ans=0; for(int i=0;i<=k;i++) Ans=(Ans+C(k+1,i)*B[i]%p*pow_(n,k+1-i))%p; Ans=Ans*inv[k+1]%p; printf("%lld\n",Ans); } return 0;}
0 0
- [51nod1228][伯努利数][自然数k次幂和]序列求和
- [51nod1228]序列求和
- 51nod1228 序列求和 (伯努利数)
- 51nod 1258 序列求和 V4 拉格朗日插值法求自然数幂和
- 高效求解自然数k次幂和的方法
- 自然数幂和 伯努利数
- 1228 序列求和 幂和+伯努利数
- 伯努利数与自然数幂和
- 自然数幂和与伯努利数 小结
- 和为n的连续自然数序列
- 自然数幂和模板
- 自然数幂和
- 自然数幂和
- 自然数幂和
- 自然数幂和 斯特林数
- 【拉格朗日插值法求自然数幂和】
- 自然数倒数平方求和
- [伯努利数] 51Nod 1258 序列求和 V4
- No result defined for action xxxAction and result input
- 北大 C++ 3.1 复制构造函数
- 模拟CloudStack的NAT实现
- 通讯录管理系统C语言课程设计
- 需求阶段如何书写Use Case
- [51nod1228][伯努利数][自然数k次幂和]序列求和
- oracle对表添加主键约束的sql语句
- Imitation- Seahorse genome
- SEO常见术语
- HDU1863 畅通工程
- 设计阶段如何画用例视图(Use-Case View)
- elasticsearch-wildcard、regexp通配符与正则表达式查询
- 110. Balanced Binary Tree
- Delphi CreateMutex 防止程序多次运行