又是一道10minAC系列的打卡题(虽说是升级版)
竟然没人A?
原题链接:戳我
题意:求 1 1 1~ 1 0 19 10^{19} 1019间均满足在 B i B_i Bi 进制下的位数是 D i D_i Di 的整数个数。
显然对于任意的位数为
D
D
D 的
B
B
B 进制数,它在十进制下的取值范围应为
B
D
−
1
~
(
B
−
1
)
∑
i
=
0
D
−
1
B
i
B^{D-1}~(B-1)\sum_{i=0}^{D-1} B^i
BD−1~(B−1)i=0∑D−1Bi 如
D
=
4
D=4
D=4,
B
=
3
B=3
B=3 时,满足条件的数最小为
(
1000
)
3
(1000)_3
(1000)3,最大为
(
2222
)
3
(2222)_3
(2222)3
注意到最大值与
B
D
−
1
B^D-1
BD−1 等价。所以范围即为
B
D
−
1
~
B
D
−
1
B^{D-1}~B^D-1
BD−1~BD−1。
由上,我们可以根据每个 B i B_i Bi 和 D i D_i Di 求出奇妙数相应的取值区间,最后取在 1 0 19 10^{19} 1019 内的公共区间即可。
观察到 n n n ≤ 1 0 7 10^7 107,显然每次求区间的操作必须是 O ( 1 ) O(1) O(1) 的。如何做到用 O ( 1 ) O(1) O(1) 的时间算出 B D − 1 B^{D-1} BD−1 ?由于 B B B 和 D D D 非常小,跑一遍预处理即可。
由于 B D B^D BD 可能爆long long,数据边界如何处理?左边界如果超出 INF ,则将左边界保存为 INF+1;右边界如果超出 INF ,则将右边界保存为 INF。
但是这里有一个数据精度的坑点。 如果采用乘法判断,则在极端数据相乘时仍有可能爆long long致使数据上溢,比如算 10 10 10 的 20 20 20 次方,算到 1 0 19 10^{19} 1019 时,仍在INF范围内,但再乘 10 10 10 就会上溢。因此要采用除法判断边界,避免运算过程中的精度上溢问题(详见代码)。
最后,如何取公共区间长度?
设每次求出的区间为
l
,
r
l,r
l,r,我们只要记录下
l
m
a
x
l_{max}
lmax 以及
r
m
i
n
r_{min}
rmin:
1
1
1) 若
l
m
a
x
l_{max}
lmax >
r
m
i
n
r_{min}
rmin,则不存在“奇妙数”,输出
0
0
0;
2
2
2) 若
l
m
a
x
l_{max}
lmax ≤
r
m
i
n
r_{min}
rmin,则输出
r
m
i
n
−
l
m
a
x
+
1
r_{min}-l_{max}+1
rmin−lmax+1。
温馨提示
● 尽量优化算法时间复杂度;
● 前
4
4
4 个测试点是专门卡数据精度的,如果精度上溢会 WA;
● 北京市第三区OI委员会提醒您:十年OI一场空,不开 long long 见祖宗。
Code
C++版(1229ms)
事实证明开了氧气后,最毒瘤的点可以轻松跑到300ms以内。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
unsigned long long gg,l,r,nl,nr;
unsigned long long a[101][21];
int n,x,y;
char ch;
inline int read()
{
ch=getchar();gg=0;
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') gg=gg*10+ch-48,ch=getchar();
return gg;
}
int main()
{
scanf("%d",&n);
l=0; r=10000000000000000000UL;
for (int i=2;i<=100;i++)
{
a[i][0]=1;
unsigned long long k=1;
for (int j=1;j<=20;j++)
{
k=k<=r/i?k*i:r+1;
a[i][j]=k;
}
}
for (int i=1;i<=n;i++)
{
x=read();y=read();
nl=a[x][y-1];nr=a[x][y]-1;
l=nl>l?nl:l;r=nr<r?nr:r;
}
if (r>=l) printf("%lld\n",r-l+1);
else printf("0");
return 0;
}
Pascal版(5005ms)
(貌似不能再优化了?跑得太慢就不放了,需要的私聊)