1 条题解
-
0
t 组输入,每组求一个大整数开立方根,输出一个小数,截断至小数点后 10 位(注意:是直接截断,不要四舍五入!),在结果前面输出一个校验和,该数字等于输出的数码之和对 10 取模。 和[HNOI2004]高精度开根 几乎一致,但是需要需要求小数点后 10 位并直接截断。实际上和这个模板题没有多少变化,只要在原始输入的数乘上一个 10的30次方,再做向下取整的牛顿迭代求高精度开根即可得到最终结果。
typedef long long ll; typedef unsigned long long ull; const ull MODD = 998244353; struct cd { double re, im; cd(double re = 0, double im = 0) : re(re), im(im) {} inline double real() const { return re; } inline double imag() const { return im; } inline void real(double re) { this->re = re; } inline void imag(double im) { this->im = im; } inline double norm() const { return re * re + im * im; } inline cd operator+(const cd& rhs) const { return cd(re + rhs.re, im + rhs.im); } inline cd operator-(const cd& rhs) const { return cd(re - rhs.re, im - rhs.im); } inline cd operator-() const { return cd(-re, -im); } inline cd operator*(const cd& rhs) const { return cd(re * rhs.re - im * rhs.im, re * rhs.im + im * rhs.re); } inline cd operator/(double x) const { return cd(re / x, im / x); } inline void operator+=(const cd& rhs) { re += rhs.re; im += rhs.im; } inline void operator/=(double x) { re /= x; im /= x; } inline void operator*=(const cd& rhs) { *this = *this * rhs; } inline friend cd conj(const cd& z) { return cd(z.re, -z.im); } inline cd operator/(const cd& rhs) const { return (*this * conj(rhs)) / rhs.norm(); } }; const int BASE = 4, MOD = 10000, LGM = 17; const double PI = 3.1415926535897932384626; class UnsignedDigit; namespace DivHelper { UnsignedDigit quasiInv(const UnsignedDigit& v); } struct UnsignedDigit { vector<int> digits; UnsignedDigit() : digits(1) {} UnsignedDigit(const vector<int>& digits); UnsignedDigit(ll x); UnsignedDigit(char* str); void print() const; string print_format() const; ull trans_normal(); bool operator<(const UnsignedDigit& rhs) const; bool operator<=(const UnsignedDigit& rhs) const; bool operator==(const UnsignedDigit& rhs) const; UnsignedDigit operator+(const UnsignedDigit& rhs) const; UnsignedDigit operator-(const UnsignedDigit& rhs) const; UnsignedDigit operator*(const UnsignedDigit& rhs) const; UnsignedDigit operator/(UnsignedDigit rhs) const; UnsignedDigit operator/(int v) const; UnsignedDigit move(int k) const; friend UnsignedDigit DivHelper::quasiInv(const UnsignedDigit& v); friend void swap(UnsignedDigit& lhs, UnsignedDigit& rhs) { swap(lhs.digits, rhs.digits); } void trim(); }; class UnsignedDecimal {}; class Int {}; class Decimal {}; namespace ConvHelper { struct FFT { int L; int brev[1 << 16]; cd w[1 << 16]; FFT() {} void init(int L) { this->L = L; for (int i = 0; i < (1 << L); ++i) brev[i] = (brev[i >> 1] >> 1) | ((i & 1) << (L - 1)); for (int i = 0; i < 1 << L; ++i) w[i] = cd(cos(i * PI * 2 / (1 << L)), sin(i * PI * 2 / (1 << L))); } void dft(cd* a, int lgn, int d) { int n = 1 << lgn; for (int i = 0; i < n; ++i) { int rv = brev[i] >> (L - lgn); if (rv < i) swap(a[rv], a[i]); } int fa = L; for (int t = 1; t < n; t <<= 1) { --fa; for (int i = 0; i < n; i += t << 1) { cd* p = a + i; for (int j = 0; j < t; ++j) { cd x = p[j + t] * w[j << fa]; p[j + t] = p[j] - x; p[j] += x; } } } if (d == -1) { reverse(a + 1, a + n); for (int i = 0; i < n; ++i) a[i] /= n; } } // realSeq FFT void dft(cd* a, cd* b, int lgn, int d) { int n = 1 << lgn; for (int i = 0; i < n; ++i) a[i].imag(b[i].real()); dft(a, lgn, d); b[0] = conj(a[0]); for (int i = 1; i < n; ++i) b[i] = conj(a[n - i]); for (int i = 0; i < n; ++i) { cd x = a[i], y = b[i]; a[i] = (x + y) / 2.; b[i] = (x - y) / cd(0, 2); } } } fft; vector<ll> conv(const vector<int>& a, const vector<int>& b) { int n = a.size() - 1, m = b.size() - 1; if (n < 100 / (m + 1) || n < 3 || m < 3) { vector<ll> ret(n + m + 1); for (int i = 0; i <= n; ++i) for (int j = 0; j <= m; ++j) ret[i + j] += a[i] * (ll)b[j]; return ret; } int lgn = 0; while ((1 << lgn) <= n + m) ++lgn; vector<cd> ta(a.begin(), a.end()), tb(b.begin(), b.end()); ta.resize(1 << lgn); tb.resize(1 << lgn); if (a == b) { fft.dft(ta.begin().base(), lgn, 1); tb = ta; } else fft.dft(ta.begin().base(), tb.begin().base(), lgn, 1); for (int i = 0; i < (1 << lgn); ++i) ta[i] *= tb[i]; fft.dft(ta.begin().base(), lgn, -1); vector<ll> ret(n + m + 1); for (int i = 0; i <= n + m; ++i) ret[i] = ta[i].real() + 0.5; return ret; } } namespace DivHelper { UnsignedDigit quasiInv(const UnsignedDigit& v) { if (v.digits.size() == 1) { UnsignedDigit tmp; tmp.digits.resize(3); tmp.digits[2] = 1; return tmp / v.digits[0]; } if (v.digits.size() == 2) { UnsignedDigit sum = 0LL, go = 1; vector<int> tmp(4); go = go.move(4); vector<UnsignedDigit> db(LGM); db[0] = v; for (int i = 1; i < LGM; ++i) db[i] = db[i - 1] + db[i - 1]; for (int i = 3; i >= 0; --i) { for (int k = LGM - 1; k >= 0; --k) if (sum + db[k].move(i) <= go) { sum = sum + db[k].move(i); tmp[i] |= 1 << k; } } return tmp; } int n = v.digits.size(), k = (n + 2) / 2; UnsignedDigit tmp = quasiInv(vector<int>(v.digits.end().base() - k, v.digits.end().base())); return (UnsignedDigit(2) * tmp).move(n - k) - (v * (tmp * tmp)).move(-2 * k); } } UnsignedDigit::UnsignedDigit(ll x) { while (x) { digits.push_back(x % MOD); x /= MOD; } if (digits.empty()) digits.push_back(0); } UnsignedDigit UnsignedDigit::move(int k) const { if (k == 0) return *this; if (k < 0) { if (-k >= digits.size()) return UnsignedDigit(); return vector<int>(digits.begin().base() + (-k), digits.end().base()); } if (digits.size() == 1 && digits[0] == 0) return UnsignedDigit(); UnsignedDigit ret; ret.digits.resize(k, 0); ret.digits.insert(ret.digits.end(), digits.begin(), digits.end()); return ret; } bool UnsignedDigit::operator<(const UnsignedDigit& rhs) const { int n = digits.size(), m = rhs.digits.size(); if (n != m) return n < m; for (int i = n - 1; i >= 0; --i) if (digits[i] != rhs.digits[i]) return digits[i] < rhs.digits[i]; return false; } bool UnsignedDigit::operator<=(const UnsignedDigit& rhs) const { int n = digits.size(), m = rhs.digits.size(); if (n != m) return n < m; for (int i = n - 1; i >= 0; --i) if (digits[i] != rhs.digits[i]) return digits[i] < rhs.digits[i]; return true; } bool UnsignedDigit::operator==(const UnsignedDigit& rhs) const { int n = digits.size(), m = rhs.digits.size(); if (n != m) return false; return memcmp(digits.begin().base(), rhs.digits.begin().base(), n) == 0; } UnsignedDigit UnsignedDigit::operator+(const UnsignedDigit& rhs) const { int n = digits.size(), m = rhs.digits.size(); vector<int> tmp = digits; if (m > n) { tmp.resize(m + 1); for (int i = 0; i < m; ++i) if ((tmp[i] += rhs.digits[i]) >= MOD) { tmp[i] -= MOD; ++tmp[i + 1]; } } else { tmp.resize(n + 1); for (int i = 0; i < m; ++i) if ((tmp[i] += rhs.digits[i]) >= MOD) { tmp[i] -= MOD; ++tmp[i + 1]; } for (int i = m; i < n; ++i) if (tmp[i] == MOD) { tmp[i] = 0; ++tmp[i + 1]; } } return tmp; } UnsignedDigit UnsignedDigit::operator*(const UnsignedDigit& rhs) const { vector<ll> tmp = ConvHelper::conv(digits, rhs.digits); for (int i = 0; i + 1 < tmp.size(); ++i) { tmp[i + 1] += tmp[i] / MOD; tmp[i] %= MOD; } while (tmp.back() >= MOD) { ll remain = tmp.back() / MOD; tmp.back() %= MOD; tmp.push_back(remain); } return vector<int>(tmp.begin(), tmp.end()); } UnsignedDigit UnsignedDigit::operator/(UnsignedDigit rhs) const { int m = digits.size(), n = rhs.digits.size(), t = 0; if (m < n) return 0LL; if (m > n * 2) t = m - 2 * n; rhs = DivHelper::quasiInv(rhs.move(t)); UnsignedDigit ret = move(t) * rhs; return ret.move(-2 * (n + t)); } UnsignedDigit UnsignedDigit::operator/(int k) const { UnsignedDigit ret; int n = digits.size(); ret.digits.resize(n); ll r = 0; for (int i = n - 1; i >= 0; --i) { r = r * MOD + digits[i]; ret.digits[i] = r / k; r %= k; } ret.trim(); return ret; } UnsignedDigit UnsignedDigit::operator-(const UnsignedDigit& rhs) const { UnsignedDigit ret(*this); int n = rhs.digits.size(); for (int i = 0; i < n; ++i) if ((ret.digits[i] -= rhs.digits[i]) < 0) { ret.digits[i] += MOD; --ret.digits[i + 1]; } ret.trim(); return ret; } UnsignedDigit::UnsignedDigit(const vector<int>& digits) : digits(digits) { if (this->digits.empty()) this->digits.resize(1); trim(); } void UnsignedDigit::trim() { while (digits.size() > 1 && digits.back() == 0) digits.pop_back(); } void UnsignedDigit::print() const { printf("%d", digits.back()); int j = 0; for (int i = (int)digits.size() - 2; i >= 0; --i) { printf("%04d", digits[i]); ++j; } //putchar('\n'); } string UnsignedDigit::print_format() const { static char s[20]; memset(s, 0, sizeof(s)); string ret = ""; sprintf(s, "%d", digits.back()); ret += string(s); int j = 0; for (int i = (int)digits.size() - 2; i >= 0; --i) { sprintf(s, "%04d", digits[i]); ret += string(s); ++j; } return ret; //putchar('\n'); } ull UnsignedDigit::trans_normal() { ull ret = 0; ull wid = 1; for (int i = 0; i < (int)digits.size(); ++i) { ret += digits[i] * wid; wid *= 10000; } return ret; } UnsignedDigit::UnsignedDigit(char* str) { int n = strlen(str); reverse(str, str + n); digits.resize((n + BASE - 1) / BASE); int cur = 1; for (int i = 0; i < n; ++i) { if (i % BASE == 0) cur = 1; digits[i / BASE] += cur * (str[i] - '0'); cur *= 10; } trim(); } char s[1000010]; void div(UnsignedDigit& a, UnsignedDigit& b, UnsignedDigit& res) { res = a / b; while ((res + 1) * b <= a) res = res + 1; while (a < res * b) res = res - 1; } UnsignedDigit pow(const UnsignedDigit& a, int b) { UnsignedDigit tmp = a, ans = 1; while (b) { if (b & 1) ans = ans * tmp; b >>= 1; tmp = tmp * tmp; } return ans; } int t; UnsignedDigit ans, tmp_ans, tmp_div, tmp_pow; int len_n, len_ans; int m; int main() { int l = ceil(log2(10086)); ConvHelper::fft.init(l + 2); scanf("%d", &t); while (t--) { m = 3; scanf("%s", s); len_n = strlen(s); //for(int i = len_n; i < len_n + 30; ++i) s[i] = '0'; s[len_n + 30] = '\0'; strcat(s, "000000000000000000000000000000"); //if (!strcmp(s, "0")) { puts("0 0.0000000000"); continue; } UnsignedDigit a(s); len_n = strlen(s); //int l = ceil(log2(len_n)); //ConvHelper::fft.init(l + 2); len_ans = (len_n + m - 1) / m; ans = 9999; ans = ans.move((len_ans) / 4); int lo = 0, hi = 9999, mi = 0; while (lo < hi) { mi = (lo + hi) >> 1; ans.digits.back() = mi; if (pow(ans, m) <= a) lo = mi + 1; else hi = mi; } ans.digits.back() = lo; ans.trim(); tmp_pow = pow(ans, m - 1); div(a, tmp_pow, tmp_div); tmp_ans = (ans * (m - 1) + tmp_div) / m; while (tmp_ans < ans) { ans = tmp_ans; tmp_pow = pow(ans, m - 1); div(a, tmp_pow, tmp_div); tmp_ans = (ans * (m - 1) + tmp_div) / m; } string output = ans.print_format(); int test_sum = 0; for (int i = 0; i < output.length(); ++i) test_sum += output[i] - 48, test_sum = test_sum >= 10 ? test_sum - 10 : test_sum; printf("%d ", test_sum); for (int i = 0; i < output.length() - 10; ++i) putchar(output[i]); putchar('.'); for (int i = output.length() - 10; i < output.length(); ++i) putchar(output[i]); putchar('\n'); } return 0; }
- 1
信息
- ID
- 966
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- (无)
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者