bzoj 3738: [Ontak2013]Kapitał 数论

       首先orz PoPoQQQ

       不过后来想了一下好像不用crt合并那么麻烦。。。注意到当n>s时(s是一个很小的常数,应该在20~30左右),显然有n!的2的次数远远大于5的次数。那么这时5被2完全抵消之后,必然有2的次数>9,因此mod 512显然=0。那么大概就可以少一半的工作量啦?

       不管了反正我抄Po爷代码。。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define mod1 512
#define mod2 1953125
using namespace std;
 
struct node{ ll x,y; }; ll n,m,k,pow1[2000005],pow2[2000005];
ll ksm(ll x,ll y,ll p){
    ll t=1; for (; y; y>>=1,x=x*x%p) if (y&1) t=(ll)t*x%p;
    return t;
}
node tms(node u,node v,ll p){
    return (node){u.x*v.x%p,u.y+v.y};
}
node dvd(node u,node v,ll p,ll phi){
    return (node){u.x*ksm(v.x,phi-1,p)%p,u.y-v.y};
}
node fct(ll x,ll p,ll q,ll *pw){
    if (!x) return (node){1,0};
    ll t=ksm(pw[q],x/q,q)*pw[x%q]%q;
    return tms((node){t,x/p},fct(x/p,p,q,pw),q);
}
void write(ll x,ll k){
    if (!k) return; write(x/10,k-1);
    printf("%lld",x%10);
}
int main(){
    scanf("%lld%lld%lld",&m,&n,&k);
    pow1[0]=pow2[0]=1; int i;
    for (i=1; i<=mod1; i++) pow1[i]=pow1[i-1]*((i&1)?i:1)%mod1;
    for (i=1; i<=mod2; i++) pow2[i]=pow2[i-1]*((i%5)?i:1)%mod2;
    node u=fct(m+n,2,mod1,pow1);
    u=dvd(u,fct(m,2,mod1,pow1),mod1,mod1>>1);
    u=dvd(u,fct(n,2,mod1,pow1),mod1,mod1>>1);
    node v=fct(m+n,5,mod2,pow2);
    v=dvd(v,fct(m,5,mod2,pow2),mod2,(mod2/5)<<2);
    v=dvd(v,fct(n,5,mod2,pow2),mod2,(mod2/5)<<2);
    ll t=min(u.y,v.y);
    ll x=u.x*ksm(2,u.y-t,mod1)%mod1*ksm(205,t,mod1)%mod1;
    ll y=v.x*ksm(5,v.y-t,mod2)%mod2*ksm(976563,t,mod2)%mod2;
    ll ans=(x*212890625+y*787109376)%1000000000;
    write(ans,k);
    return 0;
}


by lych

2016.4.22

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值