51nod 序列求和系列 簡要題解

序列求和 V1

傳送門
有個顯然的結論是 S(n)=i=1nikS(n)=\sum_{i=1}^ni^kk+1k+1 次多項式,證明可以用差分。
於是直接上拉格朗日插值即可。
CODE:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int rlen=1<<18|1;
char buf[rlen],*ib=buf,*ob=buf;
#define gc() (((ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin)),ib==ob)?-1:*ib++)
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
inline ll readl(){
	ll ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int mod=1e9+7;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?0:(a-=mod);}
inline void Dec(int&a,int b){(a-=b)<0?(a+=mod):a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))(p&1)&&(Mul(ret,a),1);return ret;}
const int N=2005;
int n,k,f[N],fac[N],ifac[N];
inline void init(int n){
	fac[0]=fac[1]=ifac[0]=ifac[1]=1;
	for(ri i=2;i<=n;++i)fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[mod-mod/i*i],mod-mod/i);
	for(ri i=2;i<=n;++i)Mul(ifac[i],ifac[i-1]);
}
inline int lagrange(int*f,int up,int x0){
	static int pre[N],suf[N];
	if(x0<=up)return f[x0];
	int res=0;
	pre[0]=suf[up+1]=1;
	for(ri i=1;i<=up;++i)pre[i]=mul(pre[i-1],x0-i);
	for(ri i=up;i;--i)suf[i]=mul(suf[i+1],x0-i);
	for(ri i=1,t;i<=up;++i){
		t=mul(f[i],mul(mul(pre[i-1],suf[i+1]),mul(ifac[i-1],ifac[up-i])));
		(up-i)&1?Dec(res,t):Add(res,t);
	}
	return res;
}
int main(){
	#ifdef ldxcaicai
	freopen("lx.in","r",stdin);
	#endif
	init(2001);
	for(ri tt=read();tt;--tt){
		n=readl()%mod,k=read();
		for(ri i=1;i<=k+2;++i)f[i]=add(f[i-1],ksm(i,k));
		cout<<lagrange(f,k+2,n)<<'\n';
	}
	return 0;
}

序列求和 V2

傳送門
要求的東西是跟 V4V4 一毛一樣的,但這裏給出一種與衆不同的推式子方法:

S(n)=i=1nriik=i=1nrij=1iSk,jCi,jj!=i=1kSk,ii!j=1nrjCj,if(x)=i=1nriCi,xf(x)=i=1nri(Ci1,x+Ci1,x1)=r(i=1nriCi,xrnCn,x+r0C0,x+i=1nriCi,x1rnCn,x1+r0C0,x1)=r(f(x)+f(x1)rnCn+1,x+C1,x)f(x)=rr1(rnCn+1,xC1,xf(x1))\begin{aligned}S(n)=&\sum\limits_{i=1}^nr^ii^k\\=&\sum\limits_{i=1}^nr^i\sum\limits_{j=1}^iS_{k,j}C_{i,j}j!\\=&\sum\limits_{i=1}^kS_{k,i}i!\sum\limits_{j=1}^nr^jC_{j,i}\\令f(x)=&\sum\limits_{i=1}^nr^iC_{i,x}\\f(x)=&\sum\limits_{i=1}^nr^i(C_{i-1,x}+C_{i-1,x-1})\\=&r(\sum\limits_{i=1}^nr^iC_{i,x}-r^nC_{n,x}+r^0C_{0,x}+\sum\limits_{i=1}^nr^iC_{i,x-1}-r^nC_{n,x-1}+r^0C_{0,x-1})\\=&r(f(x)+f(x-1)-r^nC_{n+1,x}+C_{1,x})\\\Rightarrow f(x)=&\frac r{r-1}(r^nC_{n+1,x}-C_{1,x}-f(x-1))\end{aligned}
特判掉 r=1r=1 的情況,就能夠 O(k)O(k) 遞推出整個 ff 數組,由於模數不友好可以 O(k2)O(k^2) 預處理出第二類斯特林數
時間複雜度 O(k2+Tk)O(k^2+Tk)
CODE:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int rlen=1<<18|1;
char buf[rlen],*ib=buf,*ob=buf;
#define gc() (((ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin)),ib==ob)?-1:*ib++)
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
inline ll readl(){
	ll ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int mod=1e9+7;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?0:(a-=mod);}
inline void Dec(int&a,int b){(a-=b)<0?(a+=mod):a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))(p&1)&&(Mul(ret,a),1);return ret;}
const int N=2005;
int k,r,S[N][N],fac[N],ifac[N],m,f[N];
ll n;
inline int C(int n,int m){return n<m||m<0?0:mul(fac[n],mul(ifac[m],ifac[n-m]));}
inline void init(int n){
	S[0][0]=1;
	for(ri i=1;i<=n;++i)for(ri j=1;j<=i;++j)S[i][j]=add(S[i-1][j-1],mul(S[i-1][j],j));
	fac[0]=fac[1]=ifac[0]=ifac[1]=1;
	for(ri i=2;i<=n;++i)fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[mod-mod/i*i],mod-mod/i);
	for(ri i=2;i<=n;++i)Mul(ifac[i],ifac[i-1]);
}
int main(){
	#ifdef ldxcaicai
	freopen("lx.in","r",stdin);
	#endif
	init(2001);
	for(ri res=0,tt=read();tt;--tt,res=0){
		n=readl(),k=read(),r=readl()%mod;
		m=n%(mod-1);
		n%=mod;
		f[0]=r==1?n:dec(mul(dec(ksm(r,m+1),1),ksm(dec(r,1),mod-2)),1);
		for(ri c1=mul(r,ksm(dec(r,1),mod-2)),c2=ksm(r,m),mt=n+1,i=1;i<=k;Mul(mt,dec(n+1,i++))){
			if(r^1)f[i]=mul(c1,dec(mul(c2,mul(mt,ifac[i])),add(C(1,i),f[i-1])));
			else f[i]=dec(mul(mt,mul(dec(n+1,i),ifac[i+1])),C(1,i+1));
			Add(res,mul(f[i],mul(S[k][i],fac[i])));
		}
		cout<<res<<'\n';
	}
	return 0;
}

序列求和 V3

傳送門
sbtsbt直接上式子吧(以下用 fibifib_i 表示斐波那契數列第 ii 項):
Ans=i=1nfibik=i=1n((1+52)i(152)i5)kX=1+52,Y=152=1(5)ki=1nj=0k(Xi)j(Yi)kj=1(5)kj=0ki=1n(XjYkj)i\begin{aligned}Ans=&\sum\limits_{i=1}^nfib_i^k\\=&\sum\limits_{i=1}^n(\frac{(\frac{1+\sqrt5}2)^i-(\frac{1-\sqrt5}2)^i}{\sqrt5})^k\\令X=&\frac{1+\sqrt5}2,Y=\frac{1-\sqrt5}2\\=&\frac1{(\sqrt5)^k}\sum\limits_{i=1}^n\sum\limits_{j=0}^k(X^i)^j(Y^i)^{k-j}\\=&\frac1{(\sqrt5)^k}\sum\limits_{j=0}^k\sum\limits_{i=1}^n(X^jY^{k-j})^i\end{aligned}
發現枚舉 kk 之後就是等比數列求和,搞定
然後注意模數是 1e9+91e9+9 而不是 1e9+71e9+7 因此這個時候 5\sqrt5 是有意義的可以直接暴力枚舉出來而不用重新定義一個結構體記錄虛實部
CODE:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int rlen=1<<18|1;
char buf[rlen],*ib=buf,*ob=buf;
#define gc() (((ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin)),ib==ob)?-1:*ib++)
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
inline ll readl(){
	ll ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int mod=1e9+9,sqrt5=383008016,w1=691504013,w2=308495997,INV=276601605;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?0:(a-=mod);}
inline void Dec(int&a,int b){(a-=b)<0?(a+=mod):a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))(p&1)&&(Mul(ret,a),1);return ret;}
const int N=1e5+5;
int fac[N],ifac[N],mt1[N],mt2[N],iv[N];
inline int C(int n,int m){return n<m||m<0?0:mul(fac[n],mul(ifac[m],ifac[n-m]));}
inline void init(int n){
	fac[0]=fac[1]=ifac[0]=ifac[1]=1;
	for(ri i=2;i<=n;++i)fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[mod-mod/i*i],mod-mod/i);
	for(ri i=2;i<=n;++i)Mul(ifac[i],ifac[i-1]);
	mt1[0]=mt2[0]=iv[0]=1;
	for(ri i=1;i<=n;++i)mt1[i]=mul(mt1[i-1],w1),mt2[i]=mul(mt2[i-1],w2),iv[i]=mul(iv[i-1],INV);
}
ll n;
int k,n1,n2;
inline int calc(int x){return x==1?n2:dec(mul(dec(ksm(x,n1+1),1),ksm(dec(x,1),mod-2)),1);}
int main(){
	#ifdef ldxcaicai
	freopen("lx.in","r",stdin);
	#endif
	init(100000);
	for(ri res=0,tt=read();tt;--tt,res=0){
		n=readl(),k=read();
		n1=n%(mod-1),n2=n%mod;
		for(ri t=0,x;t<=k;++t){
			x=mul(C(k,t),calc(mul(mt1[k-t],mt2[t])));
			t&1?Dec(res,x):Add(res,x);
		}
		cout<<mul(res,iv[k])<<'\n';
	}
	return 0;
}

序列求和 V4

傳送門
題解同序列求和 V1
就是把數組開大了一點
CODE:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int rlen=1<<18|1;
char buf[rlen],*ib=buf,*ob=buf;
#define gc() (((ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin)),ib==ob)?-1:*ib++)
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
inline ll readl(){
	ll ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int mod=1e9+7;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?0:(a-=mod);}
inline void Dec(int&a,int b){(a-=b)<0?(a+=mod):a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))(p&1)&&(Mul(ret,a),1);return ret;}
const int N=50005;
int n,k,f[N],fac[N],ifac[N];
inline void init(int n){
	fac[0]=fac[1]=ifac[0]=ifac[1]=1;
	for(ri i=2;i<=n;++i)fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[mod-mod/i*i],mod-mod/i);
	for(ri i=2;i<=n;++i)Mul(ifac[i],ifac[i-1]);
}
inline int lagrange(int*f,int up,int x0){
	static int pre[N],suf[N];
	if(x0<=up)return f[x0];
	int res=0;
	pre[0]=suf[up+1]=1;
	for(ri i=1;i<=up;++i)pre[i]=mul(pre[i-1],x0-i);
	for(ri i=up;i;--i)suf[i]=mul(suf[i+1],x0-i);
	for(ri i=1,t;i<=up;++i){
		t=mul(f[i],mul(mul(pre[i-1],suf[i+1]),mul(ifac[i-1],ifac[up-i])));
		(up-i)&1?Dec(res,t):Add(res,t);
	}
	return res;
}
int main(){
	#ifdef ldxcaicai
	freopen("lx.in","r",stdin);
	#endif
	init(50001);
	for(ri tt=read();tt;--tt){
		n=readl()%mod,k=read();
		for(ri i=1;i<=k+2;++i)f[i]=add(f[i-1],ksm(i,k));
		cout<<lagrange(f,k+2,n)<<'\n';
	}
	return 0;
}

序列求和 V5

傳送門
發現這個時候不能用 V2V2 的做法因爲不能快速預處理斯特林數,涼涼.jpg
然後現在要證明一個結論, S(n)=i=0n1ikri,g(x) s.t. S(n)=rng(n)g(0),deg(g)k\forall S(n)=\sum\limits_{i=0}^{n-1}i^kr^i,\exists g(x)\ s.t.\ S(n)=r^ng(n)-g(0),\deg(g)\le k
然後下面考慮在歸納法中使用微擾法來證明這個結論:

  1. k=0k=0 時,顯然成立
  2. k=tk=t 時假設成立
  3. k=t+1k=t+1 時,rS(n)=i=1n(i1)kri(r1)S(n)=i=0n1(ik(i1)k)ri+(n1)krn(1)k=rn(n1)k(1)k(rng(n)g(0))g(x)=(x1)kg(x)r1,deg(g)kS(n)=rng(n)g(0)\begin{aligned}rS(n)=&\sum\limits_{i=1}^{n}(i-1)^kr^i\\(r-1)S(n)=&-\sum\limits_{i=0}^{n-1}(i^k-(i-1)^k)r^i+(n-1)^kr^n-(-1)^k\\=&r^n(n-1)^k-(-1)^k-(r^ng(n)-g(0))\\令 g'(x)=&\frac{(x-1)^k-g(x)}{r-1},顯然 \deg(g')\le k\\\Rightarrow S(n)=&r^ng'(n)-g'(0)&\end{aligned}
    得證

由此看來,要求出 S(n+1)S(n+1) 只需知道 g(n+1)g(n+1) ,既然 g(x)g(x) 是不超過 kk 次的多項式,只需求出 g(0)g(0) ~ g(k+1)g(k+1) 即可
重新審視最初的式子並將其變形:
rng(n)g(0)=i=0n1riik=i=0n2riik+rn1(n1)k=rn1(g(n1)+(n1)k)g(0)g(n)=g(n1)+(n1)kr\begin{aligned}r^ng(n)-g(0)=&\sum\limits_{i=0}^{n-1}r^ii^k\\=&\sum_{i=0}^{n-2}r^ii^k+r^{n-1}(n-1)^k\\=&r^{n-1}(g(n-1)+(n-1)^k)-g(0)\\\Rightarrow g(n)=&\frac{g(n-1)+(n-1)^k}r\end{aligned}
這樣 g(1)g(1) ~ g(k+1)g(k+1) 均可以用 Ag(0)+BAg(0)+B 的形式表示出來,一般解決這種問題還需要建立一個等式,對於該題可以利用 k+1k+1 階差分來建立等式:
i=0k+1(1)iCk+1,ig(k+1i)=0\sum\limits_{i=0}^{k+1}(-1)^iC_{k+1,i}g(k+1-i)=0
這樣就能解出 g0g_0 然後推出 gg1,2,...,k+11,2,...,k+1 項,然後利用拉格朗日插值求出 g(n+1)g(n+1) ,最後求出 S(n+1)S(n+1)
p.s.p.s. 由上面推出的結論可以知道對於 S(n)=i=0n1f(i)riS(n)=\sum\limits_{i=0}^{n-1}f(i)r^i ,同樣存在多項式 g(x)g(x) 滿足 rng(n)g(0)=S(n)r^ng(n)-g(0)=S(n) ,且 gg 的次數不超過 ff 的次數
CODE:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int rlen=1<<18|1;
char buf[rlen],*ib=buf,*ob=buf;
#define gc() (((ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin)),ib==ob)?-1:*ib++)
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
inline ll readl(){
	ll ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int mod=985661441;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?0:(a-=mod);}
inline void Dec(int&a,int b){(a-=b)<0?(a+=mod):a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))(p&1)&&(Mul(ret,a),1);return ret;}
const int N=2e5+5;
int fac[N],ifac[N];
inline int C(int n,int m){return n<m||m<0?0:mul(fac[n],mul(ifac[m],ifac[n-m]));}
inline void init(int n){
	fac[0]=fac[1]=ifac[0]=ifac[1]=1;
	for(ri i=2;i<=n;++i)fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[mod-mod/i*i],mod-mod/i);
	for(ri i=2;i<=n;++i)Mul(ifac[i],ifac[i-1]);
}
inline int lagrange(int*a,int up,int x){
	static int pre[N],suf[N];
	if(x<=up)return a[x];
	pre[0]=suf[up+1]=1;
	for(ri i=1;i<=up;++i)pre[i]=mul(pre[i-1],x-i);
	for(ri i=up;i;--i)suf[i]=mul(suf[i+1],x-i);
	int res=0;
	for(ri t,i=1;i<=up;++i){
		t=mul(a[i],mul(mul(pre[i-1],suf[i+1]),mul(ifac[i-1],ifac[up-i])));
		(up-i)&1?Dec(res,t):Add(res,t);
	}
	return res;
}
struct F{
	int a,b;
	F(int a=0,int b=0):a(a),b(b){}
	friend inline F operator+(F a,F b){return F(add(a.a,b.a),add(a.b,b.b));}
	friend inline F operator*(F a,int b){return F(mul(a.a,b),mul(a.b,b));}
}f[N],ss;
ll n;
int k,n1,n2,r,a[N],g[N];
int main(){
	#ifdef ldxcaicai
	freopen("lx.in","r",stdin);
	#endif
	init(200001);
	for(ri tt=read();tt;--tt){
		k=read(),n=readl(),r=readl()%mod;
		if(!r){puts("0");continue;}
		for(ri i=1;i<=k+2;++i)a[i]=ksm(i,k);
		if(r==1){
			for(ri i=2;i<=k+2;++i)Add(a[i],a[i-1]);
			cout<<lagrange(a,k+2,n%mod)<<'\n';
			continue;
		}
		n1=n%mod,n2=n%(mod-1);
		f[0]=F(1,0);
		for(ri iv=ksm(r,mod-2),i=1;i<=k+1;++i)f[i]=(f[i-1]+F(0,a[i-1]))*iv;
		ss=F(0,0);
		for(ri i=0;i<=k+1;++i)ss=ss+f[k+1-i]*C(k+1,i)*(i&1?1:mod-1);
		g[0]=mul(mod-ss.b,ksm(ss.a,mod-2));
		for(ri iv=ksm(r,mod-2),i=1;i<=k+1;++i)g[i]=mul(add(g[i-1],a[i-1]),iv);
		cout<<dec(mul(lagrange(g,k+1,n1+1),ksm(r,n2+1)),g[0])<<'\n';
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章