Official

D - Digit vs Square Root Editorial by evima


Note: It is highly recommended to read the hints before reading this editorial.

Hint 0 states, “You may feel the problem setting is somewhat unnatural. In such cases, how should you approach it initially?” One way to deal with situations where you’re unsure where to start is to conduct experiments.

Let’s enumerate some of the smallest NNs that satisfy the conditions.

Experimental Code (C++)

Copy
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. long long sq(long long x){
  4. long long l=0,r=2e9;
  5. while(l<=r){
  6. long long te=(l+r)/2;
  7. if(te*te <= x){l=te+1;}
  8. else{r=te-1;}
  9. }
  10. return r;
  11. }
  12. int main(){
  13. for(long long x=1;x<=11111;x++){
  14. long long y=sq(x);
  15. string s=to_string(x);
  16. string t=to_string(y);
  17. bool ok=true;
  18. for(int i=0;i<t.size();i++){
  19. if(s[i]!=t[i]){ok=false;}
  20. }
  21. if(ok){cout << x << "\n";}
  22. }
  23. return 0;
  24. }
#include<bits/stdc++.h>

using namespace std;

long long sq(long long x){
  long long l=0,r=2e9;
  while(l<=r){
    long long te=(l+r)/2;
    if(te*te <= x){l=te+1;}
    else{r=te-1;}
  }
  return r;
}

int main(){
  for(long long x=1;x<=11111;x++){
    long long y=sq(x);
    string s=to_string(x);
    string t=to_string(y);
    bool ok=true;
    for(int i=0;i<t.size();i++){
      if(s[i]!=t[i]){ok=false;}
    }
    if(ok){cout << x << "\n";}
  }
  return 0;
}


Experimental results (dotted lines indicate that all integers in that range appear in ascending order.)

Copy
  1. 1
  2. 80
  3. 90
  4. 91
  5. ...
  6. 108
  7. 109
  8. 9800
  9. 9900
  10. 9901
  11. ...
  12. 10099
1
80
90
91
...
108
109
9800
9900
9901
...
10099

Let’s compress consecutive integers and print the result over a wider range.

Experimental Code 2 (C++)

Copy
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. long long sq(long long x){
  4. long long l=0,r=2e9;
  5. while(l<=r){
  6. long long te=(l+r)/2;
  7. if(te*te <= x){l=te+1;}
  8. else{r=te-1;}
  9. }
  10. return r;
  11. }
  12. int main(){
  13. bool pre=false;
  14. for(long long x=1;x<=111111111;x++){
  15. long long y=sq(x);
  16. string s=to_string(x);
  17. string t=to_string(y);
  18. bool ok=true;
  19. for(int i=0;i<t.size();i++){
  20. if(s[i]!=t[i]){ok=false;}
  21. }
  22. if(pre!=ok){
  23. if(ok){
  24. cout << "[ " << x << " , ";
  25. }
  26. else{
  27. cout << x-1 << " ]\n";
  28. }
  29. }
  30. pre=ok;
  31. }
  32. return 0;
  33. }
#include<bits/stdc++.h>

using namespace std;

long long sq(long long x){
  long long l=0,r=2e9;
  while(l<=r){
    long long te=(l+r)/2;
    if(te*te <= x){l=te+1;}
    else{r=te-1;}
  }
  return r;
}

int main(){
  bool pre=false;
  for(long long x=1;x<=111111111;x++){
    long long y=sq(x);
    string s=to_string(x);
    string t=to_string(y);
    bool ok=true;
    for(int i=0;i<t.size();i++){
      if(s[i]!=t[i]){ok=false;}
    }
    if(pre!=ok){
      if(ok){
        cout << "[ " << x << " , ";
      }
      else{
        cout << x-1 << " ]\n";
      }
    }
    pre=ok;
  }
  return 0;
}


Experimental results 2

Copy
  1. [ 1 , 1 ]
  2. [ 80 , 80 ]
  3. [ 90 , 109 ]
  4. [ 9800 , 9800 ]
  5. [ 9900 , 10099 ]
  6. [ 998000 , 998000 ]
  7. [ 999000 , 1000999 ]
  8. [ 99980000 , 99980000 ]
  9. [ 99990000 , 100009999 ]
[ 1 , 1 ]
[ 80 , 80 ]
[ 90 , 109 ]
[ 9800 , 9800 ]
[ 9900 , 10099 ]
[ 998000 , 998000 ]
[ 999000 , 1000999 ]
[ 99980000 , 99980000 ]
[ 99990000 , 100009999 ]

From here, it seems we can draw the following conclusion (let’s call it Fact A):

  • Let K=10K=10. (This KK represents the base)
  • The set of integers that satisfy the conditions is a union of intervals of the following forms:
    • [1,1][1,1]
    • [K2iKi,K2i+Ki1][K^{2i}-K^i, K^{2i}+K^i-1] (i1)(i \ge 1)
    • [K2i2Ki,K2i2Ki][K^{2i}-2K^i, K^{2i}-2K^i] (i1)(i \ge 1)

This is indeed correct.

Assuming Fact A, the following solution works:

  • Considering the constraint N1018N \le 10^{18}, the range of ii to consider is 1i91 \le i \le 9.
  • Also, the intervals mentioned in Fact A are all disjoint (have no common parts).
  • Therefore, for a single NN, by determining the intersection between [1,N][1,N] and the 1919 intervals and summing up their lengths, the problem can be solved.

The time complexity per test case is O(1)O(1).

Sample implementation (C++):

Copy
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. using pl=pair<long long,long long>;
  4. int main(){
  5. ios::sync_with_stdio(false);
  6. cin.tie(nullptr);
  7. vector<pl> segs={{1,1}};
  8. long long k2=1,k1=1;
  9. for(long long i=1;i<=9;i++){
  10. k2*=100; k1*=10;
  11. segs.push_back({k2-2*k1,k2-2*k1});
  12. segs.push_back({k2-k1,k2+k1-1});
  13. }
  14. // for(auto &nx : segs){
  15. // cout << nx.first << " " << nx.second << "\n";
  16. // }
  17. int t;
  18. cin >> t;
  19. while(t>0){
  20. t--;
  21. long long n;
  22. cin >> n;
  23. long long res=0;
  24. for(auto &nx : segs){
  25. long long l=nx.first;
  26. long long r=min(n,nx.second);
  27. if(l<=r){res+=(r-l+1);}
  28. }
  29. cout << res << "\n";
  30. }
  31. return 0;
  32. }
#include<bits/stdc++.h>

using namespace std;
using pl=pair<long long,long long>;

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  vector<pl> segs={{1,1}};
  long long k2=1,k1=1;
  for(long long i=1;i<=9;i++){
    k2*=100; k1*=10;
    segs.push_back({k2-2*k1,k2-2*k1});
    segs.push_back({k2-k1,k2+k1-1});
  }
  // for(auto &nx : segs){
  //   cout << nx.first << " " << nx.second << "\n";
  // }

  int t;
  cin >> t;
  while(t>0){
    t--;
    long long n;
    cin >> n;
    long long res=0;
    for(auto &nx : segs){
      long long l=nx.first;
      long long r=min(n,nx.second);
      if(l<=r){res+=(r-l+1);}
    }
    cout << res << "\n";
  }
  return 0;
}




Now, let’s prove Fact A.

First, we fix the number of digits for xx and yy. There are two patterns to consider:

  • yy has i+1i+1 digits, xx has 2i+12i+1 digits (Pattern 1)
  • yy has ii digits, xx has 2i2i digits (Pattern 2)

For simplicity, we assume that cases where xx and yy have very small numbers of digits have been proved by exhaustive search.

On Pattern 1

Fix the prefix y=Ki+Cy=K^i + C (C0)( C \ge 0 ). Then,

  • From the square root condition, xx should be within [(Ki+C)2,(Ki+C+1)21][(K^i+C)^2, (K^i+C+1)^2-1]
  • From the prefix condition, xx should be within [(Ki+C)Ki,(Ki+C+1)Ki1][(K^i + C) K^i, (K^i + C + 1) K^i - 1]

Organizing this,

  • The left end of the square root condition is K2i+2KiC+C2K^{2i} + 2K^iC + C^2.
  • The right end of the prefix condition is K2i+KiC+Ki1K^{2i} + K^iC + K^i - 1.

When C1C \ge 1, comparing these,

K2i+2KiC+C2>K2i+KiC+Ki1K^{2i} + 2K^iC + C^2 > K^{2i} + K^iC + K^i - 1
Ki(C1)+C2+1>0\Leftrightarrow K^i(C-1) + C^2 + 1 > 0

This shows that no integers satisfy the conditions.

For the remaining case C=0C=0, we get an interval of integers that satisfy the conditions: [K2i,K2i+Ki1][K^{2i},K^{2i}+K^i-1] (S1).

On Pattern 2

Let us have a similar discussion as in Pattern 1.
Fix the prefix y=KiCy=K^i - C (0<C<Ki)( 0 < C < K^i ). Then,

  • From the square root condition, xx should be within [(KiC)2,(KiC+1)21][(K^i - C)^2, (K^i - C+1)^2-1]
  • From the prefix condition, xx should be within [(KiC)Ki,(KiC+1)Ki1][(K^i - C) K^i, (K^i - C + 1) K^i - 1]

Organizing this,

  • The right end of the square root condition is K2i2KiC+2Ki+C22CK^{2i} - 2K^iC + 2K^i + C^2 - 2C
  • The left end of the prefix condition is K2iKiCK^{2i} - K^iC

Comparing these,
K2i2KiC+2Ki+C22C<K2iKiCK^{2i} - 2K^iC + 2K^i + C^2 - 2C < K^{2i} - K^iC
C22C<KiC2Ki\Leftrightarrow C^2 - 2C < K^iC - 2K^i
C(C2)<Ki(C2)\Leftrightarrow C(C-2) < K^i (C-2)
If this holds, that is, when 2<C<Ki2 < C < K^i, the two intervals do not overlap.

Now, let’s process the cases C=1,2C=1,2.

For C=2C=2, we get an interval of integers that satisfy the conditions: [K2i2Ki,K2i2Ki][K^{2i} - 2K^i, K^{2i} - 2K^i] (S2).

For C=1C=1, we get an interval of integers that satisfy the conditions: [K2iKi,K2i1][K^{2i} - K^i, K^{2i} - 1] (S3).

Putting (S1), (S2), and (S3) together proves Fact A. ■

Bonus! Let’s consider methods to handle constraints like N10200000N \le 10^{200000} or the case K10K \neq 10.

posted:
last update:



2025-04-06 (Sun)
05:13:30 +00:00