/*
1)改题:刚开始看错题目了,把题目看成求这个数的位数,然后就错了,不过如果把题目改成求C(n,r)*p^q的位数,也是
一个不错的小题目。那样的话就用到了:1)用log(base)n+1 求n在base进制下的位数.
2)log换底公式和其它一些简单公式。代码如下:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define maxn 1000005
double fac[maxn];
void get_fac(){ //记录{ log1,...logn }前i项的和
fac[0]=0;
for(int i=1;i<maxn;i++){
fac[i]=fac[i-1]+log(i*1.0);
}
}
int main(){
int i,j,n,t,r,p,q;
get_fac();
cin>>t;
for(i=1;i<=t;i++){
scanf("%d%d%d%d",&n,&r,&p,&q);
int ans=(int)((fac[n]-fac[n-r]-fac[r]+q*log(p*1.0))/log(10.0))+1;
printf("Case %d: %d\n",i,ans);
}
return 0;
}
2) 这道题目是求有几个后缀0,想了一下,刚开始想的是可以把这个式子分解成好多项相乘,要出现一个10,则个位为 2*5, 4*5, 6*5, 8*5 或者看末位有几个0.所以对一个数,
首先看这个数的末位有几个0,这样的话进位问题会出错,于是有进一步考虑了下,知道了思路:10=2*5.这样就不用考虑进位问题了,所以问题转化为求每个数中可以因式分解
出几个2和几个5,然后看这个式子中总共有几个2和5就可以解决问题,所以预处理1-1000000中每个数有几个2和5,因为2^20,5^9就足够,所以暴力时间复杂度就够了。剩下的
就简单了。
后来看别人的题解,发现他直接求n!的x因子的算法挺巧妙的,就摘过来了:
int fac(int x , int y){//x!的y因子的个数
int s = 0 ;
while(x){
s += x/y ;
x /= y ;
}
return s ;
}
*/
下面是我的程序:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 1000005
int num2[maxn],num5[maxn],fac2[maxn],fac5[maxn];
//求出每个数2和5这两个因子的个数
void get_num(){
memset(num2,0,sizeof(num2));
memset(num5,0,sizeof(num5));
for(int i=1;i<maxn;i++){
if(i%2==0){
int k=i;
while(k%2==0){num2[i]++; k/=2;}
}
if(i%5==0){
int k=i;
while(k%5==0){num5[i]++; k/=5; }
}
}
}
//打表出前i个数中一共含有几个2和5,存在fac数组中
void get_fac(){
fac2[0]=0; fac5[0]=0;
for(int i=1;i<maxn;i++) {
fac2[i]=fac2[i-1]+num2[i];
fac5[i]=fac5[i-1]+num5[i];
}
}
int main(){
int i,j,n,t,r,p,q;
get_num();
get_fac();
cin>>t;
for(i=1;i<=t;i++){
scanf("%d%d%d%d",&n,&r,&p,&q);
int n2=fac2[n]-fac2[n-r]-fac2[r]+q*num2[p];
int n5=fac5[n]-fac5[n-r]-fac5[r]+q*num5[p];
int ans=min(n2,n5);
printf("Case %d: %d\n",i,ans);
}
return 0;
}