n!最右非零数字
来源:互联网 发布:淘宝投诉卖家后果 编辑:程序博客网 时间:2024/06/08 10:43
n!最右非零数字
注此文大部分来自luoyuchu的blog
+ ##Description:
给出正整数N(可能有前导0),请求出N!最右非零的数位的值
+ ##Range:
n<=10^100
+ HDU1066 弱化问题USACO 3.2.1
以前做USACO暴力水过了 这是多么的愚昧于是我去学习了一下
考虑虑到末位的0 是由于 2 * 5 这样的运算而产生的,那么我们把2与5成对的剔除就不会出现精度问题了?
其实问题还可以继续深入思考。我们考虑在 10^1000 下如何解决问题
我们考虑一个分组问题
我们按10 分组 这样是可以做的
我们任然可以按 奇偶分组,仍然是可以做的
任然还有按20分组的方案来自吉大的模板
这道题其实就是抓住分组利用规律 进而利用一张小表 推出大表 这种思想是极好的
- ##Solution:
####若设答案为x,如果用C表示 [n/5] + [n/25] + [n/125] + …, 那么需要求的是下面的同余方程
####*10^(c+1)*可分解为*2^(c+1)*与*5^(c+1)*即为
####当 n > 1 时所有的偶数都是上面的方程组中第一个方程的解,而且, n > 1 时第一个方程没有奇数解,因此 n > 1 时只需要虑第二个方程的符合 0 < x <9 的偶数解:
####用 h(n) 表示 所有与 5 互素且不大于 n 的正整数的连乘积, 则 n! 可以表为
####代入方程,消去 5 的乘方后得到下面的同余方程
####由于 3 * 2 ≡ 1 (mod5), 因此方程变为
####由 Euler-Fermat 公式知( % 表示求模运算 )
####由 Wilson 定理有
####把上面两式代入 (c) 就得到了
####于是就可以通过O(logn)的时间求出答案
- ##my_code:
#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cstdlib>#include <ctime>#define dig(...) fprintf(stderr, __VA_ARGS__)#define REP(i, n) for (int i = 1, _end_ = (n); i <= _end_; ++i)const int mod = 10000;const int maxs = 105;const int pp[5] = {1, 6, 2, 8, 4};using namespace std;struct Bignum{ int w; int t[maxs]; Bignum() {w = 0, memset(t, 0, sizeof(t));}};Bignum operator + (const Bignum &a, const Bignum &b){ Bignum s; s.w = max(a.w, b.w); for (int i = 1; i <= s.w; ++i) s.t[i] = a.t[i] + b.t[i]; for (int i = 1; i <= s.w; ++i) { if (i == s.w && s.t[i] >= mod) ++s.w; s.t[i + 1] += s.t[i] / mod; s.t[i] %= mod; } return s;}void divide(Bignum &s, int b, int &my){ for (int i = s.w; i >= 1; --i) { s.t[i - 1] += mod * (s.t[i] % b); s.t[i] /= b; if (i == s.w && s.t[i] == 0) --s.w; } my = s.t[0] / mod; s.t[0] = 0;}int Ans = 1;int n;Bignum source;void test(Bignum source){ printf("%d", source.t[source.w]); for (int i = source.w - 1; i >= 1; --i) printf("%04d", source.t[i]); printf("----%d\n", source.w);}void Init(){ char t; int k; int w = 0; int num[maxs] = {0}; memset(source.t, 0, sizeof(source.t)); Ans = 1; while ((t = getchar()) < '1' || t > '9'); do num[++w] = t - '0'; while((t = getchar()) >= '0' && t <= '9'); REP(i, w / 2) swap(num[i], num[w - i + 1]); for (int i = 1; i <= w; i += 4) { k = 0; for (int j = i + 3; j >= i; --j) k = k * 10 + num[j]; source.t[i / 4 + 1] = k; } source.w = (w + 3) / 4;}void Work(){ int my; Bignum c; Bignum s = source; do { divide(s, 5, my); c = c + s; REP(i, my) Ans *= i; Ans %= 5; }while (s.w); if (c.t[1] & 1) Ans *= -1; divide(c, 4, my); REP(i, my) Ans *= 3; Ans = (Ans + 1000) % 5; if (source.w == 1 && source.t[1] == 1) cout << pp[0] << endl; else cout << pp[Ans] << endl;}int main(){ int T; freopen("a.in", "r", stdin); freopen("a.out", "w", stdout); scanf("%d", &T); while (T--) { Init(); Work(); } fclose(stdin); fclose(stdout); return 0;}
0 0
- n!最右非零数字
- N×N数字
- N*N数组插入数字
- n位数字
- 求N^N第一位数字(数学)
- N^N 数字的最右边
- n^n的末位数字
- 1004 n^n的末位数字
- n^n的末位数字
- 1004 n^n的末位数字
- 取数字问题(M*N)
- 取N个随机数字
- 如何计算n! 有几位数字
- 数字n的所有子集
- 3n+1 数字处理
- 求n^n和n!的最左边的数字
- 求n^n和n!的最左边的数字
- 【错难题】n阶数字正方形/n阶数字三角形/n阶递减三角形
- 指纹解锁和手势解锁
- av_find_stream_info
- 最大类间方差法(大津法,OTSU)
- rthrt
- HDOJ 3696 Farm Game 【spfa】
- n!最右非零数字
- enable_shared_from_this使用
- 拦截导弹
- UVA - 11008 Antimatter Ray Clearcutting
- egwef
- 查看android-support-v4的源码的几种方法【转】
- afvaw
- C++程序运行时间计算
- linux shell 递归拷贝文件