您的位置:首页 > 其它

SRM 510 DIV2 1000 TheLuckyBasesDivTwo

2016-09-13 16:35 260 查看
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;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: