Codeforces 717A. Festival Organization(数列递推+下降幂转化)

传送门
这题就是本题的强行二合一。。。
先考虑我们有这么一个问题:
假设我们知道 a i = A x n + B y n a_i=Ax^n+By^n ai=Axn+Byn
现在要求 ∑ i = l r C a i k \sum_{i=l}^rC_{a_i}^k i=lrCaik
要求在 O ( k 2 log ⁡ r ) O(k^2\log r) O(k2logr)的时间内求出
那么 A n s = 1 k ! ∑ i = l r a i k ‾ Ans=\frac1{k!}\sum_{i=l}^ra_i^{\underline k} Ans=k!1i=lraik
= 1 k ! ∑ i = l r ∑ j = 0 k a i j ∗ s s ( k , j ) =\frac1{k!}\sum_{i=l}^r\sum_{j=0}^ka_i^j*s_s(k,j) =k!1i=lrj=0kaijss(k,j)
= 1 k ! ∑ i = 0 k s s ( k , j ) ∑ j = l r a j i =\frac1{k!}\sum_{i=0}^ks_s(k,j)\sum_{j=l}^ra_j^i =k!1i=0kss(k,j)j=lraji
考虑前面的一个 ∑ O ( k ) \sum O(k) O(k)枚举
现在要快速求出 ∑ i = l r a i k \sum_{i=l}^ra_i^k i=lraik
于是我们把 a i a_i ai的表达式带进去:
A n s ′ = ∑ i = l r ( A x i + B y i ) k Ans'=\sum_{i=l}^r(Ax^i+By^i)^k Ans=i=lr(Axi+Byi)k
A n s ′ = ∑ i = l r ∑ j = 0 k C k j A j B k − j ( x j y k − j ) i Ans'=\sum_{i=l}^r\sum_{j=0}^kC_{k}^{j}A^jB^{k-j}(x^jy^{k-j})^i Ans=i=lrj=0kCkjAjBkj(xjykj)i
A n s ′ = ∑ i = 0 k C k i A i B k − i ∑ j = l r ( x i y k − i ) j Ans'=\sum_{i=0}^kC_{k}^{i}A^iB^{k-i}\sum_{j=l}^r(x^iy^{k-i})^j Ans=i=0kCkiAiBkij=lr(xiyki)j
然后发现最后一个 ∑ \sum 可以等比数列 O ( log ⁡ r ) O(\log r) O(logr)的时间求出。
于是这部分的复杂度是 O ( k log ⁡ r ) O(k\log r) O(klogr)
总时间复杂度是 O ( k 2 log ⁡ r ) O(k^2\log r) O(k2logr)
然后对于本题, f i = f i b i + 2 f_i=fib_{i+2} fi=fibi+2
f i b n = 1 5 ( 1 + 5 2 ) n − 1 5 ( 1 − 5 2 ) n fib_n=\frac{1}{\sqrt5}(\frac{1+\sqrt5}2)^n-\frac{1}{\sqrt5}(\frac{1-\sqrt5}2)^n fibn=5 1(21+5 )n5 1(215 )n
发现 f f f的通项公式带有 5 \sqrt5 5 ,且 x 2 ≡ 5 m o d    1000000007 x^2\equiv 5 \mod 1000000007 x25mod1000000007无解
于是要用扩域的方法解决,即每个数用 a + b 5 a+b\sqrt5 a+b5 的形式表示。
代码:

#include
#define ri register int
using namespace std;
typedef long long ll;
const int mod=1e9+7;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline void Add(int&a,const int&b){a=a+b>=mod?a+b-mod:a+b;}
inline void Dec(int&a,const int&b){a=a>=b?a-b:a-b+mod;}
inline void Mul(int&a,const int&b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,a=mul(a,a))if(p&1)Mul(ret,a);return ret;}
const int N=205;
struct cp{
	int x,y;
	cp(int x=0,int y=0):x(x),y(y){}
	friend inline cp operator+(const cp&a,const cp&b){return cp(add(a.x,b.x),add(a.y,b.y));}
	friend inline cp operator-(const cp&a,const cp&b){return cp(dec(a.x,b.x),dec(a.y,b.y));}
	friend inline cp operator*(const cp&a,const cp&b){return cp(add(mul(a.x,b.x),mul(5,mul(a.y,b.y))),add(mul(a.x,b.y),mul(a.y,b.x)));}
	friend inline cp operator*(const cp&a,const int&b){return cp(mul(a.x,b),mul(a.y,b));}
	friend inline cp operator/(const cp&a,const cp&b){
		int t=ksm(dec(mul(b.x,b.x),mul(5,mul(b.y,b.y))),mod-2);
		return cp(mul(t,dec(mul(a.x,b.x),mul(5,mul(a.y,b.y)))),mul(t,dec(mul(a.y,b.x),mul(a.x,b.y))));
	}
	friend inline cp operator^(cp a,int p){cp ret=cp(1,0);for(;p;p>>=1,a=a*a)if(p&1)ret=ret*a;return ret;}
	friend inline cp operator^(cp a,ll p){cp ret=cp(1,0);for(;p;p>>=1,a=a*a)if(p&1)ret=ret*a;return ret;}
}A,B,X,Y,ans;
int C[N][N],s[N][N],k;
ll l,r;
inline void init(const int&up){
	s[0][0]=1;
	for(ri i=0;i<=up;++i){
		C[i][0]=C[i][i]=1;
		for(ri j=1;j<i;++j)C[i][j]=add(C[i-1][j-1],C[i-1][j]);
	}
	for(ri i=1;i<=up;++i)for(ri j=1;j<=i;++j)s[i][j]=add(s[i-1][j-1],mul(s[i-1][j],i-1));
	A=cp(0,ksm(5,mod-2)),B=cp(0,mod-ksm(5,mod-2));
	X=cp((mod+1)>>1,(mod+1)>>1),Y=cp((mod+1)>>1,mod-((mod+1)>>1));
}
inline cp S(cp x,int k){
	if(x.x==1&&x.y==0)return x*((r-l+1)%mod);
	return (x^l)*(((x^(r-l+1))-cp(1,0))/(x-cp(1,0)));
}
inline cp calc(int k){
	cp ret;
	for(ri i=0;i<=k;++i)ret=ret+(S((X^i)*(Y^(k-i)),i)*((A^i)*(B^(k-i)))*C[k][i]);
	return ret;
}
int main(){
	cin>>k>>l>>r,l+=2,r+=2;
	init(k);
	cp t;
	ri mt=1;
	for(ri i=0;i<=k;++i)t=calc(i)*s[k][i],(k+i)&1?ans=ans-t:ans=ans+t,Mul(mt,i?i:1);
	cout<<mul(ans.x,ksm(mt,mod-2));
	return 0;
}

你可能感兴趣的:(#,组合数学,#,二次剩余,#,斯特林数)