【bzoj1300】大数计算器

题意:

求C(n,m) 如果C(n,m)的位数<=12 那么直接输出 否则按XXX...XXXXXXXXX的形式输出

题解:

这题之前打过 但是昨天又想出一种新的做法 先说下新的做法吧- -

________________(坑爹的博客园出现了一些bug 不能显示回车 so 我是华丽的分割线)________________

首先要知道位数 显然可以用res存 如果是乘的res就加log(10,x) 除的就减掉

如果res<13那么暴力算 直接输出就完了

如果res>=13 就要知道前3位 和答案模10^10的值

前3位很简单 把res的整数部分边成2 10^res的整数部分就是前3位

后面要算C(n,m)%10^10的值 我们发现10^10=(2^10)*(5^10)

就把要乘或除的数a 转换成a=a'*(2^x)*(5^y) (a',10)=1

把2和5的次方分离出来算 那么就能保证运算的数都和10^10互质 就能用乘法逆元了

_________________________________________________________________________________

但是这有个问题- -

10^10*10^10可能会爆long long

对这问题有两种办法解决

1.高精 不解释

2.分别算模2^10 和模5^10 最后线性模方程算答案

鉴于这两种方法都听难打 而且bzoj还把这题变成高富帅题 于是我放弃治疗了- -

_________________________________________________________________________________

正解:

我们可以把每个数都分解质因数 因为n和m都比较小 所以可以把每个质数的指数都存下来 最后统一算就完了

_________________________________________________________________________________

代码:

ContractedBlock.gif ExpandedBlockStart.gif
 1 #include <cstdio>
 2 #include <cmath>
 3 using namespace std;
 4 typedef long long ll;
 5 const ll mo=1000000000000ll;
 6 ll n,m,ans=1,num,sum[1000001],bo[1000001],primer[1000001],ns;
 7 double save;
 8 ll power(ll a,ll b){
 9             ll res=1;
10             for (;b;b>>=1){
11                 if (b&1) res=res*a%mo;
12                 a=a*a%mo;
13             }
14             return res;
15 }
16 void makepr(ll t){
17      for (ll i=2;i<=t;i++){
18          if (!bo[i]) primer[++ns]=i;
19          for (ll j=1;j<=ns && i*primer[j]<=t;j++){
20              bo[i*primer[j]]=1;
21              if (i%primer[j]==0) break;
22          }
23      }
24 }
25 int main(){
26     freopen("bz1300.in","r",stdin);
27     freopen("bz1300.out","w",stdout);
28     ll i,j;
29     scanf("%I64d%I64d\n",&n,&m);
30     makepr(n);
31     for (i=1;i<=ns;i++){
32         for (j=primer[i];j<=n;j*=primer[i]) sum[i]+=n/j;
33         for (j=primer[i];j<=m;j*=primer[i]) sum[i]-=m/j;
34         for (j=primer[i];j<=n-m;j*=primer[i]) sum[i]-=(n-m)/j;
35     }
36     for (i=1;i<=ns;i++)
37     if (sum[i]){
38                 ans=(ans*power(primer[i],sum[i]))%mo;
39                 save+=log10(primer[i])*sum[i];
40     }
41     if (save<12) printf("%I64d",ans);
42     else{
43          long double ans2=pow(10,save-static_cast<int>(std::floor(save))+2);
44          printf("%I64d...%I64d",static_cast<ll>(floor(ans2)),ans%(mo/1000));
45     }
46     fclose(stdin);
47     fclose(stdout);
48 } 
View Code

转载于:https://www.cnblogs.com/g-word/p/3377953.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值