题意是:给出Anum 的定义.为 包含7或者是该数可以被7整除的数。 a[i]=Anum;
Bnum的定义是,为Anum的子集但是 如果i为Anum,a[i]对应的值就不是Bnum。
即如 A[7] 对应的Anum=35 不是Bnum 所以 B[7] 为37(第7个Bnum数)
思路: 先二分一个数mid ,找到<=mid 的mid最小的区间满足等于n个Bnum的数 ,此数就是
,如何求区间内Bnum 的数量呢,,先求Anum的数量,然后对Anum的数量(即为下标)这个区间再求Anum 的数量,
两者相减就是Bnum的数量了 、。
即:
此题需要注意的地方,1.会超 long long 所以要用unsigned longlong 否则会TLE, 2 定义的类型容易全部都写成int类型。 3 二分的写法。
#include <cstdio> ///此代码书写的时候出现了LL 定义成了int的情况
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#include<cmath>
#include<cstdlib>
#define LL unsigned long long
#define bug puts("***********")
#define INF 0x3f3f3f3f
using namespace std;
const LL R=((LL)1<<63)-1;
int num=0;
int bit[100];
LL dp[100][100][2];
LL DFS(int p,int m,int have,int flag)
{
if(p==0) return have||(m==0);
if(flag&&dp[p][m][have]!=-1) return dp[p][m][have];
int k=flag?9:bit[p];
LL sum=0;
for(int i=0; i<=k; i++)
{
sum=sum+DFS(p-1,(m*10+i)%7,i==7||have,flag||i!=k);
}
if(flag) dp[p][m][have]=sum;
return sum;
}
LL solve(LL x)
{
if(x<0)
return 0;
num=0;
while(x)
{
bit[++num]=x%10;
x/=10;
}
return DFS(num,0,0,0)-1;
}
LL get(LL m)
{
LL ans1=solve(m); /// LL
return ans1-solve(ans1); ///Anum - num(下标是Anum的数的 个数)
}
int main()
{
LL n;
while(~scanf("%lld",&n))
{
memset(dp,-1,sizeof(dp));
/// cout<<get(n)<<endl;
LL high =R;
//cout<<pow(2,63)-1;
LL low=0;
LL ans=0;
LL num1,num2,num3;
while(low<=high)
{
LL mid=(high+low)>>1;
num2=get(mid);
/// 这种二分的方法不对,因为并不是唯一的一个mid对应一个num2,
///而是存在多个mid对应一个num2 的情况,并且应该取符合条件的最小mid才行
// if(num2==n) .
// {
// ans=mid;
// break;
// }
// else if(num2>n)
// high=mid-1;
// else
// low=mid+1;
if(num2<n)
low=mid+1;
else
{
ans=mid;
high=mid-1;
}
}
printf("%lld\n",ans);
}
return 0;
}