zzuli 2184 河南多校联萌(5)(非二分)

来源:互联网 发布:90后听的经典网络歌曲 编辑:程序博客网 时间:2024/05/01 21:44

Description

每一个数都有若干个后缀零,比如100有2个、10有1个、1有0个,那么问题来了,已知整数n,求x使其满足x!的后缀零个数为n
Input

输入一个数T (≤ 10000),表示有T组数据
接下来T行每一行有一个数n (1 ≤ n≤10^8)
Output

每组数据首先输出当前组数(格式参见Sample Output),之后输出满足情况时最小的x,如果x不存在,输出no
Sample Input

3
1
2
5
Sample Output

Case 1: 5
Case 2: 10
Case 3: no

题意很简单 ,给一个n求一个最小的x,使x满足x!的后缀零个数为n;找不到输出no
想要在乘法中产生0,要么乘以一个后缀零不为0的数,要么乘以一个5的倍数,细想一下,后缀零不为0的数 一定是5的倍数,所以 只要题目就是求 一个最小的x使x!中5的因子个数;
首先最容易想到的从5开始5个数5个数的加,循环遍历,直到5的因子个数达到n,但是这样写肯定超时。
标程是用二分,可以解。
这里我给出一个非二分的解题方法;本质仍然是暴力;
思路:上面说一次+5暴力循环会超时,那么就想到如果一次+25/125/625/3125是否可行?
如果题读懂很容易能想到一个东西,从1开始每5个数的积5的因子个数是1(小于25的情况下),eg:1-5的积5的因子个数是1,5-10的积5的因子个数是1…
每25个数的积5的因子个数是6(小于125的情况下),eg:1-25的积5的因子个数是6,26-50的积5的因子个数是6….,这个很好算,拿1-25举例,1-25可以分成5组,有4组的积5的因子个数是1,含25的那一组因为25这个数特殊 这一组的积5的因子个数是2;
往下递推 可以得出
1开始每5个数的积5的因子个数是1(小于25的情况下)
每25个数的积5的因子个数是6(小于125的情况下)
每125个数的积5的因子个数是31(小于625的情况下)
每625个数的积5的因子个数是156(小于3125的情况下)
这样可以事先存两个数组;

int a[100],b[100];    a[0]=1;    b[0]=5;    for(int i=1;i<=15;i++)    {        b[i]=b[i-1]*5;        a[i]=a[i-1]*5+1;    }

这两个数组的含义是:eg:b[2]=125,a[2]=156;代表每125个数可以提供31个后缀零;
之后就是暴力了 eg:n=400的时候

首先一个循环在a数组内找到n在哪个位置

int flag=0; for(int i=1;i<=15;i++)        {            if(n<=a[i])            {                flag=i-1;                break;            }        }

得出flag=3,说明a[4],b[4]所代表的每3125个数可以提供780个后缀零太多,不能一次+a[4]=3125,只能一次+625;
下面是一个while循环
1.看看可以+几个625,即int ans1=n/a[flag];
2.设一个ans变量 记录目前为止有多少个后缀零了, ans+=ans1*a[flag];
3.设一个sum变量记录目前加到哪个数了, sum+=ans1*b[flag];
4.更新n的值n-=ans1*a[flag];
5.判断如果正好能够加5次 即ans==5的时候 ans要再+1,(想不明白参照上面 “每25个数的积5的因子个数是6”那一段)
6.如果ans<所需要的后缀零的个数,flag–返回第1步;
以n=400为例 手动模拟上述过程:
1.ans1=400/156=2;
2.ans+=2*156=312;
3.sum+=2*625=1250;
4.n=400-2*156=88;
5.ans1==2 不加
6.ans=312<400 flag– 返回第一步
1.ans1=88/31=2;
2.ans+=2*31=374;
3.sum+=2*125=1500;
4.n=88-2*31=26;
5.ans1==2 不加
6.ans=374<400 flag– 返回第一步
1.ans1=26/6=4;
2.ans+=4*6=398;
3.sum+=4*25=1600;
4.n=22-4*6=2;
5.ans1==4 不加
6.ans=398<400 flag– 返回第一步
1.ans1=2/1=2;
2.ans+=2*1=400;
3.sum+=2*5=1610;
4.n=2-2*1=0;
5.ans1==2 不加
6.ans=400==400 跳出
最后再判断如果ans>400 输出no
否则输出 sum

全代码

#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<algorithm>using namespace std;int main(){    int a[100],b[100];    a[0]=1;    b[0]=5;    for(int i=1;i<=15;i++)    {        b[i]=b[i-1]*5;        a[i]=a[i-1]*5+1;    }    int n,t;    scanf("%d",&t);    int e=0;    while(t--)    {        e++;        scanf("%d",&n);        int flag=0;        for(int i=1;i<=15;i++)        {            if(n<=a[i])            {                flag=i-1;                break;            }        }        int sum=0;        int ans=0;        int d=n;        while(ans<d)        {            int ans1=n/a[flag];            ans+=a[flag]*ans1;            sum+=ans1*b[flag];            n-=ans1*a[flag];            if(ans1==5)                ans++;            flag--;        }        if(ans>d)            printf("Case %d: no\n",e);        else            printf("Case %d: %d\n",e,sum);    }                                                                 return 0;}                                    
原创粉丝点击