[原创]第四届山东省赛 A-Number and B-Number [数位dp+二分答案]【动态规划】

2017-03-11 23:13:13 Tabris_ 阅读数:375


博客爬取于2020-06-14 22:41:20
以下为正文

版权声明:本文为Tabris原创文章,未经博主允许不得私自转载。
https://blog.csdn.net/qq_33184171/article/details/61441552


题目链接:hrbust的oj上有题目

————————————————————————————————
A-Number and B-Number
Time Limit: 1000 MS Memory Limit: 32768 K
Total Submit: 22(8 users) Total Accepted: 5(5 users) Rating: Special Judge: No
Description
Tom is very interested in number problem. Nowadays he is thinking of a problem about A-number and B-number.

A-number is a positive integer whose decimal form contains 7 or it can be divided by 7. We can write down the first 10 A-number ( a[i] is the ith A-number)

{a[1]=7,a[2]=14,a[3]=17,a[4]=21,a[5]=27,a[6]=28,a[7]=35,a[8]=37,a[9]=42,a[10]=47};

B-number is Sub-sequence of A-number which contains all A-number but a[k] ( that k is a A-number.) Like 35, is the 7th A-number and 7 is also an A-number so the 35 ( a[7] ) is not a B-number. We also can write down the first 10 B-number.

{b[1]=7,b[2]=14,b[3]=17,b[4]=21,b[5]=27,b[6]=28,b[7]=37,b[8]=42,b[9]=47,b[10]=49};

Now Given an integer N, please output the Nth B-number.

Input
The input consists of multiple test cases.

For each test case, there will be a positive integer N as the description.(0<N<2631)(0< N< 2^{63}-1)

Output
For each test case, output an integer indicating the Nth B-number.

You can assume the result will be no more then 2^63-1.

Sample Input
1
7
100
Sample Output
7
37
470

——————————————————————————————————

题目大意:
A数组就是民间游戏"敲七"的序列
B数组就是{xxi{A}i{A}}\{x \big| x_i \in \{A\} 且 i\notin \{A\}\}
然后输出B数组中第n个元素即:BnB_n

解题思路:

如果直接求第i个元素的话 无论是A数组还是B数组都不能求(反正我不会)

但是他求得是第ii个元素 我们可以换一个角度来思考

首先我们可以用一个入门级别的数位dp来统计小于nn的元素个数,

那么反过来 [1,n]中 最小的有x个元素的n 就是第x个元素

那么我们就可以用二分答案来统计了

对于A数组我们很好数位dp
但是对于B数组我们不能直接求出来

但是考虑A与B数组的关系,发现,只要对cal(x)统计的结果ans在统计一下相减即可;

即:

1
2
A = cal(x);
B = A - cal(A);

注意
二分溢出的问题
最大值要(1<<63)-1,

附本题代码
——————————————————————————————————————————————

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# include<bits/stdc++.h>

using namespace std;
typedef long long int LL;
/********************************/

int num[20];
LL dp[20][8][2];

LL dfs(int pos,int mod,int limit,int status){
if(pos<0) return (status||mod%7==0);
if(dp[pos][mod][status]!=-1&&!limit) return dp[pos][mod][status]; //忘写 limit 懵逼1000天有没有

int endi=9;
if(limit) endi=num[pos];

LL res = 0;
for(int i=0;i<=endi;i++)
res+=dfs(pos-1,(mod*10+i)%7,limit&&i==endi,i==7||status);

if(!limit) dp[pos][mod][status] = res;
return res;
}

LL cal(LL x){
if(!x) return 0;
int len=0;
while(x) num[len++]=x%10,x/=10;
return dfs(len-1,0,1,0)-1;
}

void solve(LL x){
LL l=7,r=(1ll<<63)-1,mid,ans=-1; //r写成1e18 wa懵逼有没有,,,,

while(l<=r){
mid=((r-l)>>1)+l;
LL tmp = cal(mid);
tmp -= cal(tmp);
if(tmp>=x)ans=mid,r=mid-1;
else l=mid+1;
}
printf("%lld\n",ans);
}

int main(){
// printf("%lld\n",~(1ll<<63));
memset(dp,-1,sizeof(dp));
LL n;
while(~scanf("%lld",&n)) solve(n);
return 0;
}