SRM 510 DIV2 1000 TheLuckyBasesDivTwo

来源:互联网 发布:java开发mes系统 编辑:程序博客网 时间:2024/04/27 17:39

Task:

给你一个数N,把N在B进制中的转化存进一个数组S,若能满足

S[0]B0+S[1]B1+S[2]B2+...+S[t]Bt==N
并且S[i]要么为4,要么为7,对于这样的一个B,我们称它为N的Lucky数,求N的Lucky数有多少个,若有无限个,则输出-1.(1<=N<=1e12)

Solution:

首先判掉N==4||N==7,这样的话,一定有无数种Lucky数(只需B>N).

对于一个这么大的N,我们可以发现不能用枚举所有进制直接判,而显然可以看出进制的基数一定小于N,所以又少了一点(虽然根本没什么用),然后我们去看当转化完之后只有两位的话,那么第一位与第二位只可能是:(4,7),(4,4),(7,7),(7,4).

又有S[0]B0+S[1]B1==N,那么就可以直接算B了,再判一下B是否比S[0]和S[1]大就好了.

下面就是位数大于三的时候了.我们有S[0]B0+S[1]B1+S[2]B2==N,那么N>=S[2]B2,即B<=N.

那么就直接枚举i 从1到N,再去判断是否满足就好了.

但是这种方法的代码没有打……

看懂的就可以去敲了,没看懂的话……

那么就来看我的方法吧(开始耍无赖)……

我们先去枚举一个S数组,表示最终会有的转化后的结果.这个可以用O(2mx)枚举出来(因为mx不会很大,最多为log51e12(因为至少也要是5的进制).

那么枚举出最后的数组之后,怎么去算是否成立呢?

二分是你的最佳选择.我们可以看出如果B越大,那么转换来的数一定也会越大.显然满足二分.这里还有个小Bug,就是说你在进制转化时可能会爆long long,这时只要判一下过程中有没有值溢出后小于0即可.

int S[25];LL ans,tp;LL Ex(LL Base,int x){//转换进制      LL re=0,B=1;    for(int i=0;i<=x;i++){        re+=B*S[i];        if(re<0)return 1LL*INF*INF;        B*=Base;        if(S[i]>=Base)return -1;    }    return re;}void judge(int x){    LL L=1,R=1e12;    while(L<=R){        LL mid=L+R>>1;        LL sw=Ex(mid,x);        if(sw>tp)R=mid-1;        else if(sw<tp)L=mid+1;        else if(sw==tp){            ans++;            return;        }    }}void dfs(int x){//枚举最后转化的数组     if(x==17)return;    S[x]=4;//加上一个 4     judge(x);    dfs(x+1);    S[x]=7;//加上一个 7      judge(x);    dfs(x+1);}class TheLuckyBasesDivTwo {public:    long long find(long long n) {        bool f=true;        ans=0;tp=n;        if(n==4||n==7)return -1;        dfs(0);        return ans;    }};
0 0
原创粉丝点击