BZOJ 3738 Ontak2013 Kapitał 数论

42 篇文章 0 订阅

题目大意:求C(n+m,n)去掉末尾所有的0之后的后k位

组合数取模问题……首先k<=9,所以我们考虑直接mod 10^9

将10^9分解质因数,可以得到10^9=2^9*5^9=512*1953125 这两个数都不是很大 所以直接套用组合数取模的模板

具体细节参见 2142 礼物 http://blog.csdn.net/popoqqq/article/details/39891263

消0的时候注意消掉2的时候要乘上相应5的逆元 消5同理

#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define P1 512ll
#define P2 1953125ll
using namespace std;
typedef long long ll;
typedef pair<ll,ll> abcd;
ll n,m,k;
ll power1[P1+1],power2[P2+1];
ll Quick_Power(ll x,ll y,ll p)
{
    ll re=1;
    while(y)
    {
        if(y&1) re*=x,re%=p;
        x*=x,x%=p;
        y>>=1;
    }
    return re;
}
abcd Plus(const abcd x,const abcd y,ll p)
{
    return abcd(x.first*y.first%p,x.second+y.second);
}
abcd Minus(const abcd x,const abcd y,ll p,ll phi_p)
{
    return abcd(x.first*Quick_Power(y.first,phi_p-1,p)%p,x.second-y.second);
}
abcd Find(ll x,ll p,ll p_a,ll pow[])
{
    ll i,temp;
    if(!x) return abcd(1,0);
    temp=Quick_Power(pow[p_a],x/p_a,p_a)*pow[x%p_a]%p_a;
    return Plus(abcd(temp,x/p),Find(x/p,p,p_a,pow),p_a);
}
int main()
{
    int i;
    power1[0]=power2[0]=1;
    for(i=1;i<=P1;i++) power1[i]=power1[i-1]*(i%2?i:1)%P1;
    for(i=1;i<=P2;i++) power2[i]=power2[i-1]*(i%5?i:1)%P2;
    cin>>n>>m>>k;
    abcd p1=Find(n+m,2,P1,power1);
    p1=Minus(p1,Find(n,2,P1,power1),P1,P1/2*1);
    p1=Minus(p1,Find(m,2,P1,power1),P1,P1/2*1);
    abcd p2=Find(n+m,5,P2,power2);
    p2=Minus(p2,Find(n,5,P2,power2),P2,P2/5*4);
    p2=Minus(p2,Find(m,5,P2,power2),P2,P2/5*4);
    ll temp=min(p1.second,p2.second);
    ll x=p1.first*Quick_Power(2,p1.second-temp,P1)%P1*Quick_Power(205,temp,P1)%P1;
    ll y=p2.first*Quick_Power(5,p2.second-temp,P2)%P2*Quick_Power(976563,temp,P2)%P2;
    ll ans=(1953125*109*x+512*1537323*y)%1000000000;
    cout<<setfill('0')<<setw(k)<<ans%Quick_Power(10,k,1000000001)<<endl;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值