Fibonacci Sum(二项式求和)

在这里插入图片描述在这里插入图片描述
这道题没写过类似的感觉确实不好想,考点在与二项式求和优化等式。特别是优化等式这里,是真的坑。
废话不多说,上推到过程:
因为:
在这里插入图片描述
可以有:
在这里插入图片描述
所以有二项式展开:

在这里插入图片描述
很明显竖起来是等比,所以这样就可以把复杂度变成klogn了;
然后可以得出公式S结果公式为:

在这里插入图片描述
由于需要mod1e9+9,所以可以由费马小定理可知变形为:

在这里插入图片描述

qi的值和阶乘的值都可以预处理,但是你会发现如果直接带这个公式写出来就T了。这就是真的变态卡快速幂。。。。。。。。。
这是我超时的代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll P = 1e9+9;
const ll maxn = 1e5+5;
ll a[maxn],b[maxn],jie[maxn];
void pre(){
	jie[0]=1;
	//预处理阶乘
	for(ll i=1;i<maxn;i++)jie[i]=jie[i-1]*i%P;
	//预处理a,b
	a[0]=1;b[0]=1;
	for(ll i=1;i<maxn;i++){
		a[i]=a[i-1]*691504013%P;//a的%P的逆元
		b[i]=b[i-1]*308495997%P;//b的%p的逆元
	}
}
ll QP(ll x,ll n){
      ll res=1;
      while(n){
      	if(n&1){
      		 res=res*x%P;
		  }
		  x=x*x%P;
		  n>>=1;
	  }
	  return res;
}
ll T;
ll N,C,K;
int main(){
	scanf("%lld",&T);
	pre();
	ll ans=0;
		 ll x=QP(383008016,P-2);//利用费马小定理求1/sqrt(5)%P的值
		  
	while(T--){
	     ans=0;
		scanf("%lld %lld %lld",&N,&C,&K);
		ll t=QP(a[K],C)%P;
		for(ll i=0;i<=K;i++){
			ll fenzi=jie[K];
			ll fenmu=jie[i]*jie[K-i]%P;
			ll res=fenzi*QP(fenmu,P-2)%P;
			ll temp=t*(QP(t,N)-1)%P*QP(t-1,P-2)%P;//这里有个十分奇葩的地方,我开头把他分开写居然wa了而不是T了。。。。。。。
			if(t==1){//分母没有意义,求和可知为N 
				temp=N%P;
			}
			temp=temp*res%P;
			if(i&1) ans-=temp;//如果为负数
			else ans+=temp;//如果为正数
			ans%=P;
		}

	 ans=QP(x,K)*ans%P;
	 ans=(ans%P+P)%P;//防止负数
	 printf("%lld\n",ans);
	}
	
	return 0;
} 

然后就很懵逼了,这怎么搞的?????崩溃。。。。。。。
参考大佬的代码优化因为后一个q的值就是前一个q的值乘上A(-C)*B^C;
AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; 
const ll mod=1e9+9;
const ll MAXN=1e5;
ll factor[MAXN+10];
ll invFactor[MAXN+10];
ll invn[MAXN+10];
const ll A=691504013;
const ll invA=691504012;
const ll B=308495997;
const ll D=276601605;
ll QP(ll x, ll n)
{
    ll res=1;
    while(n)
    {
        if (n&1) res=res*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}
ll Mod(ll a, ll b)
{
    a+=b;
    if (a>=mod)
        a-=mod;
    return a;
}
void pre()
{
    factor[0]=invFactor[0]=invn[0]=factor[1]=invFactor[1]=invn[1]=1;
    for(int i=2; i<=MAXN; i++)
    {
        factor[i]=factor[i-1]*i%mod;
        invn[i]=(ll) (mod-mod/i)*invn[mod%i]%mod;
        invFactor[i]=invFactor[i-1]*invn[i]%mod;
    }
}
ll getC(ll m, ll n)//求C(n,m) 
{
    if (n<0 || m<0 || m>n)
        return 0;
    ll ans=factor[n];
    ans=(ll) ans*invFactor[m]%mod;
    ans=(ll) ans*invFactor[n-m]%mod;
    return ans;
}
int main()
{
    pre();
    int T;
    scanf("%d", &T);
    while(T--)
    {
        ll n, c, k;
        scanf("%lld%lld%lld", &n, &c, &k);
        ll ans=0;
        ll a1=QP(QP(A, k), c%(mod-1));
        ll q=QP((ll) invA*B%mod, c%(mod-1));
        ll n1=n%mod;
        ll n2=n%(mod-1);
        ll a1power=QP(a1, n2);
        ll qpower=QP(q, n2);
        for(int i=0; i<=k; i++)
        {
            ll sum=getC(i, k);
            if (i&1)
            {
                sum=mod-sum;
            }
            if (a1==1)
            {
                ans=(ans+sum*n1%mod)%mod;
            }
            else
            {
                sum=sum*(a1*(a1power-1+mod)%mod)%mod;
                sum=sum*QP(a1-1, mod-2)%mod;
                ans=Mod(ans, sum);
            }
            a1=a1*q%mod;
            a1power=a1power*qpower%mod;
        }
        printf("%lld\n",ans*QP(D,k)%mod);
    }
}

实属想不到。。。。。。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值