【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都比较小 所以可以把每个质数的指数都存下来 最后统一算就完了
_________________________________________________________________________________
代码:
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 }