萌新求助 P1362 打表
查看原帖
萌新求助 P1362 打表
109217
天有不测风云楼主2021/10/16 08:23

思路:使用暴力算法每隔 30000003000000 个数字求答案,打出一张表,再使用类似分块的算法求解。

打表代码

#include <iostream>
#include <cstdio>
#define int long long
using namespace std;

template<typename T> inline T read() {
    T X = 0; bool flag = 1; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') flag = 0; ch = getchar();}
    while (ch >= '0' && ch <= '9') {X = (X << 1) + (X << 3) + ch - '0'; ch = getchar();}
    if (flag) return X;
    return ~ (X - 1);
}

template<typename T> inline void write(T X) {
    if (X < 0) {putchar('-'); X = ~ (X - 1);}
    int s[50], top = 0;
    while (X) {s[++top] = X % 10; X /= 10;}
    if (!top) s[++top] = 0;
    while (top) putchar(s[top--] + '0');
    putchar(',');
  putchar(' ');
    return;
}

inline int S(int n) { //S 函数
    int ans = 0;
    while (n) {
        ans += n % 10;
        n /= 10;
    }
    return ans;
}

inline bool check(int n) {
    if (S(n * n) == S(n) * S(n)) {
        return true;
    }
    return false;
}

signed main() {
  for (int l = 1, r = 3000000; r <= 1000000000; l += 3000000, r += 3000000,
           (r > 1000000000 && r < 1003000000) ? (r = 1000000000) : (r = r)) {
           //从 l = 1, r = 3000000 开始循环,每次 l 和 r 加 3000000,如果超过了 1000000000 就把块的右边界移至 1000000000
    int ans = 0;
    for (int i = l; i <= r; i++) {
      ans += check(i);
    }
    write(ans);
  }
  putchar('\n');
  return 0;
}

提交的代码

#include <cstdio>
#include <iostream>
#define int long long
#define pl(n) (n / 3000000)
using namespace std;

const int len = 3000000;
int anss[505] = {
    1373, 60, 0,   967, 183, 0,   303, 242, 0, 1,  114, 0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   1011,
    202,  0,  471, 470, 0,   1,   312, 0,   0, 56, 0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 353, 294,
    0,    1,  311, 0,   0,   171, 0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 1, 120, 0,
    0,    98, 0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  0,   0, 0, 0, 0, 0,   0,
    0,    0,  0,   0,   0,   0,   0,   0,   0, 0,  1};

template <typename T>
inline T read() {
  T X = 0;
  bool flag = 1;
  char ch = getchar();
  while (ch < '0' || ch > '9') {
    if (ch == '-') flag = 0;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    X = (X << 1) + (X << 3) + ch - '0';
    ch = getchar();
  }
  if (flag) return X;
  return ~(X - 1);
}

template <typename T>
inline void write(T X) {
  if (X < 0) {
    putchar('-');
    X = ~(X - 1);
  }
  int s[50], top = 0;
  while (X) {
    s[++top] = X % 10;
    X /= 10;
  }
  if (!top) s[++top] = 0;
  while (top) putchar(s[top--] + '0');
  putchar('\n');
  return;
}

inline int S(int n) { //S 函数
  int ans = 0;
  while (n) {
    ans += n % 10;
    n /= 10;
  }
  return ans;
}

inline bool check(int n) {
  if (S(n * n) == S(n) * S(n)) {
    return true;
  }
  return false;
}

signed main() {
  int l = read<int>(), r = read<int>();
  int ans = 0;
  if (pl(l) == pl(r)) { //如果左端点和右端点在同一个块内,暴力解决
    for (int i = l; i <= r; i++) {
      ans += check(i);
    }
  } else { //否则,使用类似分块的放大解决
    for (register int i = l; pl(i) == pl(l); ++i) ans += check(i);
    for (register int i = pl(l) + 1; i <= pl(r) - 1; i++) ans += anss[i];
    for (register int i = r; pl(i) == pl(r); --i) ans += check(i);
  }
  write(ans);
  return 0;
}

此代码只有 30 分;通过乱改表中数字可得 90 分代码,但是没有理论依据。

求求了,帮萌新调个题呗

2021/10/16 08:23
加载中...