一道丧心病狂的卡常题,又教会了我许多卡常技巧
首先,我们可以推一下答案的式子:
当a==b时:
否则:
接下来,就是把模板打上,然而。。。T了!
注意到模数为,发现可以分解为,那么中国剩余定理由循环变为了一个式子
而且,扩展lucas的模数只有两个
扩展Lucas中最耗时的是什么?求阶乘!
如果模数只有两个,那么。。。
预处理!
于是,我们的lucas跑得飞快
还有一个问题:除以二怎么办?膜意义下2没有逆元
我们发现如果 a+b 是奇数,那么我们需要计算的式子其实是杨辉三角中间对称的几列,那么我们只计算左边的几列或者右边的几列就可以除2了,但是在a+b为偶数的时候我们会发现剩下了一个 情况会有点棘手
但是我们注意到根据帕斯卡恒等式(杨辉三角)可以得到
于是我们计算 就可以了
————转自https://www.luogu.org/blog/ShadowassIIXVIIIIV/solution-p3726
其实吧,还有一个地方要卡
在Lucas中计算 2 / 5 的数量时,若发现它≥k,就可以直接返回0啦
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll M;
ll ksm(ll x,ll y,ll P)
{
ll ret=1;
while (y)
{
if (y&1) ret=ret*x%P;
x=x*x%P;
y>>=1;
}
return ret;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
ll d=a;
if (b) d=exgcd(b,a%b,y,x),y-=a/b*x;
else x=1,y=0;
return d;
}
ll inv(ll t,ll p){ll x,y;exgcd(t,p,x,y);return (x%p+p)%p;}
ll f[2][2000000];
void init(ll p,ll pr)
{
bool c=(p!=2);f[c][0]=1;
for (ll i=1;i<=pr;i++)
{
f[c][i]=f[c][i-1];
if (i%p) f[c][i]=f[c][i]*i%pr;
}
}
ll calc(ll n,ll p,ll pr)
{
if (!n||n==1) return 1ll;
return ksm(f[p!=2][pr-1],n/pr,pr)*f[p!=2][n%pr]%pr*calc(n/p,p,pr)%pr;
}
ll a,b,K;
ll C(ll n,ll m,ll p,ll pr)
{
ll i,j,k,x=0;
if (n==m) return 1;
if (n<m) return 0;
for (i=p;i<=n;i*=p) x+=n/i-m/i-(n-m)/i;
if (x>K) return 0; // !!!!!
i=calc(n,p,pr);j=inv(calc(m,p,pr),pr);k=inv(calc(n-m,p,pr),pr);
return i*j%pr*k%pr*ksm(p,x,pr)%pr;
}
ll pr2,pr5,inv_2,inv_5;
ll CRT(ll n,ll m){return C(n,m,2,pr2)*pr5%M*inv_5+C(n,m,5,pr5)*pr2%M*inv_2%M;}
int nb[22];
inline void print(ll x,ll k)
{
for(int i=1;i<=10;i++)nb[i]=0;
for(int i=1;x;i++,x/=10)nb[i]=x%10;
for(int i=k;i>=1;i--)printf("%d",nb[i]);printf("\n");
}
int main()
{
init(2,512); init(5,1953125);
while (~scanf("%lld %lld %lld",&a,&b,&K))
{
ll ans=0;
M=ksm(10,K,(ll)1e10);pr2=1<<K;pr5=M/pr2;
inv_2=inv(pr2,pr5),inv_5=inv(pr5,pr2);
if (!(a^b)) ans=((ksm(2,a+b-1,M)-CRT(a*2-1,a))%M+M)%M;
else
{
for (ll i=1;i<=(a-b-1)>>1;i++) ans+=CRT(a+b,i+b),ans%=M;
if ((a+b-1)&1) ans+=CRT(a+b-1,(a+b)>>1);
ans%=M;
ans+=ksm(2,a+b-1,M);
}
print(ans%M,K);
}
}