题目
小G正在寻找一种特殊类型的数字,它具有以下特征:它们有 n n n位数字。将这个数除以两半得到两个完全平方数,可能有前导零。可以保证 n ≡ 0 m o d 2 n \equiv 0 \bmod 2 n≡0mod2,(这个的意思其实就是,n一定是偶数,即一定能对半分)
现在小G想知道在 [ L , R ] [L, R] [L,R]范围内有多少这样的数。
这两半的长度必须相同。
输入
行
1
1
1:一个整数
n
n
n。
行
2
2
2:两个整数
L
L
L和
R
R
R。
数据范围
1 ≤ n ≤ 60 1\leq n\leq 60 1≤n≤60, 1 0 n − 1 ≤ L ≤ R < 1 0 n 10^{n-1} \le L \le R < 10^n 10n−1≤L≤R<10n.
思路
这题的思路其实很简单,主要难点在与数据范围
1
0
60
10^{60}
1060以及远远超于long long的范围了,所以在这,要么python,要么开__int128。
以及,在这里还有个点药注意,因为
1
0
30
10^{30}
1030已经超过了signed double
的范围(52位数,
2
52
2^{52}
252=4.5e16左右),所以这里的sqrt会出现向上取整的情况。
例如16个9,因为已经超signed double了,所以它不会以16个9的方式存入,而是会以,1e16 -1的方式存入,这个时候,开方就是1e8,但实际上开方出来为1e8-1。因此,这里的开放要手写二分
__int128
__int128 就是占用128字节的整数存储类型。由于是二进制,范围就是 -2127~2127-1,如果使用了 unsigned __int128,则范围变成 00 ~ 21282128,即约39位数,这在一定程度上可以替代高精度运算实现大数运算,而且操作难度更低,所以在数据范围不超过的情况下,都可以使__int128。
操作
_int128只能实现四则运算,不能用cin,cout,scanf,printf输入输出,所以需要用到写个快读和快写的函数;
快读
__int128 read()
{
//直接在函数里面实现读字符串操作更简洁
__int128 res=0;//初始结果赋值0
char scan[1005];
scanf("%s",scan);
for(int i=0;i<strlen(scan);i++)
res*=10,res+=scan[i]-'0';//实现进位
return res;//返回__int128类型
}
快写
void print(__int128 num)
{//递归调用,实现从高位向低位输出
if(num>9)
print(num/10);
putchar(num%10+'0');
}
sqrt问题
1.要么特判
x = sqrt(num-1)
//或者
if(x * x > num) x=x-1
2.要么手写二分
__int128_t sqr(__int128_t x) {
__int128_t l = 0, r = 4e15;
while (r > l) {
__int128_t mid = (l + r + 1) / 2;
if (mid * mid > x) r = mid - 1;
else l = mid;
}
return l;
}
代码
#include<bits/stdc++.h>
using namespace std;
#define i128 __int128
#define int long long
void print(__int128 num) {
//递归调用,实现从高位向低位输出
if(num>9)
print(num/10);
putchar(num%10+'0');
}
__int128_t sqr(__int128_t x) {
__int128_t l = 0, r = 4e15;
while (r > l) {
__int128_t mid = (l + r + 1) / 2;
if (mid * mid > x) r = mid - 1;
else l = mid;
}
return l;
}
i128 qiu(i128 x,i128 y) {
i128 res=0;
i128 xx=sqr(x);
i128 yy=sqr(y);
res+=yy-xx;
if(xx*xx>=x) {
res+=1;
}
return res;
}
void solve() {
int n;
char C;
cin>>n;
i128 a=0,b=0,c=0,d=0,maxn=0;
for(int i=0; i<n/2; i++) {
cin>>C;
a*=10;
a+=C-'0';
}
for(int i=0; i<n/2; i++) {
cin>>C;
b*=10;
b+=C-'0';
}
for(int i=0; i<n/2; i++) {
cin>>C;
c*=10;
c+=C-'0';
}
for(int i=0; i<n/2; i++) {
cin>>C;
d*=10;
d+=C-'0';
}
for(int i=0; i<n/2; i++) {
maxn*=10;
maxn+=9;
}
i128 ans=0;
if(a==c) {
if((sqr(a)*sqr(a))==a) {
print(qiu(b,d));
} else {
cout<<0;
}
return;
}
if((sqr(a)*sqr(a))==a) {
ans+=qiu(b,maxn);
}
if((sqr(c)*sqr(c))==c) {
ans+=qiu(0,d);
}
ans+=qiu(a+1,c-1)*qiu(0,maxn);
print(ans);
cout<<"\n";
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t--) solve();
return 0;
}
附上大佬的解释