zoukankan      html  css  js  c++  java
  • hihocoder1639 图书馆 [数学]

    已知数组a[]及其和sum, 求sum! / (a1!a2!...an!) 的个位数的值。

    求某数的逆元表写成了求某数阶乘的逆元表,故一直没找到错误。

    P 是质数的幂
    B 表示质数,P 表示模数,cal(n) 将返回 n!,以 a × B^b 形式表示,a为模P的情况下。

     1 ll n,x,y,P,B,s[2000000];
     2 ll exgcd(ll a,ll b){
     3     if(!b)return x=1,y=0,a;
     4     ll d=exgcd(b,a%b),t=x;
     5     return x=y,y=t-a/b*y,d;
     6 }
     7 ll rev(ll a,ll P){exgcd(a,P);while(x<0)x+=P;return x%P;}
     8 ll pow(ll a,ll b,ll P){ll t=1;for(;b;b>>=1LL,a=a*a%P)if(b&1LL)t=t*a%P;return t;}
     9 struct Num{
    10     ll a,b;
    11     Num(ll a = 1, ll b = 0): a(a), b(b){}
    12     Num operator*(Num x){return Num(a*x.a%P, b+x.b);}
    13     Num operator/(Num x){return Num(a*rev(x.a,P)%P, b-x.b);}
    14 };
    15 Num cal(ll n){return n? Num(s[n%P]*pow(s[P],n/P,P)%P,n/B)*cal(n/B): Num();}
    16 void pre(){
    17     for(int i = s[0] = 1; i < P; i++) 
    18         if(i%B) s[i]=s[i-1]*i%P; 
    19         else s[i] = s[i-1];
    20     s[P] = s[P-1];
    21 }
    22 int main(){
    23     B = 2, P = 512, pre();
    24     cal(n);
    25 }
    View Code

    hihocoder1639 别人的题解

    自己的题解如下:

      1 #include <bits/stdc++.h>
      2 
      3 #define ll long long
      4 #define ull unsigned long long
      5 #define st first
      6 #define nd second
      7 #define pii pair<int, int>
      8 #define pil pair<int, ll>
      9 #define pli pair<ll, int>
     10 #define pll pair<ll, ll>
     11 #define tiii tuple<int, int, int>
     12 #define pw(x) ((1LL)<<(x))
     13 #define lson l, m, rt<<1
     14 #define rson m+1, r, rt<<1|1
     15 #define sqr(x) ((x)*(x))
     16 #define SIZE(A) ((int)(A.size()))
     17 #define LENGTH(A) ((int)(A.length()))
     18 #define FIN freopen("A.in","r",stdin);
     19 #define FOUT freopen("A.out","w",stdout);
     20 using namespace std;
     21 /***********/
     22 template<typename T>
     23 bool scan (T &ret) {
     24     char c;
     25     int sgn;
     26     if (c = getchar(), c == EOF) return 0; //EOF
     27     while (c != '-' && (c < '0' || c > '9') ) c = getchar();
     28     sgn = (c == '-') ? -1 : 1;
     29     ret = (c == '-') ? 0 : (c - '0');
     30     while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
     31     ret *= sgn;
     32     return 1;
     33 }
     34 template<typename N,typename PN>inline N flo(N a,PN b){return a>=0?a/b:-((-a-1)/b)-1;}
     35 template<typename N,typename PN>inline N cei(N a,PN b){return a>0?(a-1)/b+1:-(-a/b);}
     36 template<typename T>inline int sgn(T a) {return a>0?1:(a<0?-1:0);}
     37 template<class T> int countbit(const T &n) { return (n==0)?0:(1+countbit(n&(n-1))); }
     38 template <class T1, class T2>
     39 bool gmax(T1 &a, const T2 &b) { return a < b? a = b, 1:0;}
     40 template <class T1, class T2>
     41 bool gmin(T1 &a, const T2 &b) { return a > b? a = b, 1:0;}
     42 template <class T> inline T lowbit(T x) {return x&(-x);}
     43 
     44 template<class T1, class T2>
     45 ostream& operator <<(ostream &out, pair<T1, T2> p) {
     46     return out << "(" << p.st << ", " << p.nd << ")";
     47 }
     48 template<class A, class B, class C>
     49 ostream& operator <<(ostream &out, tuple<A, B, C> t) {
     50     return out << "(" << get<0>(t) << ", " << get<1>(t) << ", " << get<2>(t) << ")";
     51 }
     52 template<class T>
     53 ostream& operator <<(ostream &out, vector<T> vec) {
     54     out << "("; for(auto &x: vec) out << x << ", "; return out << ")";
     55 }
     56 void testTle(int &a){
     57     while(1) a = a*(ll)a%1000000007;
     58 }
     59 const ll inf = 0x3f3f3f3f;
     60 const ll INF = 1e17;
     61 const int mod = 1e9+7;
     62 const double eps = 1e-5;
     63 const int N = 100000+10;
     64 const double pi = acos(-1.0);
     65 
     66 /***********/
     67 
     68 
     69 int quick(int x, long long n, int mod) {
     70     int ans = 1;
     71     while(n) {
     72         if(n&1) ans = ans*x%mod;
     73         x = x*x%mod;
     74         n >>= 1;
     75     }
     76     return ans;
     77 }
     78 
     79 long long get2(long long n) {
     80     long long ans = 0;
     81     while(n >>= 1)
     82         ans += n;
     83     return ans;
     84 }
     85 
     86 int m[] = {1, 1, 2, 1, 4}; //阶乘%5
     87 int inv[] = {1, 1, 3, 2, 4}; //i的逆元,写成i!的逆元,狂WA
     88 pair<long long, int> get5(long long n) {
     89     if(n < 5) return {0, m[n]};
     90     pair<long long, int> ret = get5(n/5);
     91     ret.st += n/5;
     92     ret.nd = ret.nd*quick(m[4], n/5, 5)*m[n%5]%5;
     93     return ret;
     94 }
     95 
     96 
     97 
     98 int main() {
     99     int T; scanf("%d", &T);
    100     long long a[1000];
    101     while(T--) {
    102         int n; scanf("%d", &n);
    103         long long sum = 0;
    104         for(int i = 0; i < n; i++)
    105             scanf("%lld", a+i), sum += a[i];
    106         long long mod2 = get2(sum);
    107         auto mod5 = get5(sum);
    108         for(int i = 0; i < n; i++) {
    109             mod2 -= get2(a[i]);
    110             auto ret = get5(a[i]);
    111             mod5.st -= ret.st;
    112             mod5.nd = mod5.nd*inv[ret.nd]%5;
    113         }
    114         int ans;
    115         if(mod5.st) ans = mod2? 0: 5;
    116         else {
    117             ans = mod5.nd;
    118             if(mod2) {
    119                 if(ans&1) ans = (ans+5)%10;
    120             }
    121             else {
    122                 if(!(ans&1)) ans = (ans+5)%10;
    123             }
    124         }
    125         printf("%d
    ", ans);
    126     }
    127     return 0;
    128 }
    View Code

    附:

    一句话阐明如何求阶乘的末尾非0数

    求末尾非0数模5的值,n = 5k时,

    n! = (1*2*3*4) * (6*7*8*9) * ... * (5k-4)*(5k-3)*(5k-2)*(5k-1)  *5^k * k!

        = (1*2*3*4/2) * (6*7*8*9/2) * ... * [(5k-4)*(5k-3)*(5k-2)*(5k-1)/2]  *10^k * k!

        = (1*2*3*4/2) * (6*7*8*9/2) * ... * [(5k-4)*(5k-3)*(5k-2)*(5k-1)/2]  * k!  (去掉末尾的几个零,结果不变)

        = (1*2*3*4/2) * (6*7*8*9/2) * ... * [(5k-4)*(5k-3)*(5k-2)*(5k-1)/2]  *6^k * k! (乘6,模5下末尾不变)

        = (1*2*3*4*3) * (6*7*8*9*3) * ... * [(5k-4)*(5k-3)*(5k-2)*(5k-1)*3]  * k!

        = 2^k * k!

    阶乘末两位非0数

    P = 4, B = 2;

    P = 25, B = 5

    再合并一下~

    组合数求模

  • 相关阅读:
    async/await语法
    generator生成器函数
    数组练习
    解决异步(重点promise函数)
    iterator遍历器
    各种遍历方法(重点for....of)
    ES6代理proxy
    Symbol新数据类型
    函数(rest 箭头)
    ES6常用方法(字符串,数字,数组,对象)
  • 原文地址:https://www.cnblogs.com/dirge/p/8735645.html
Copyright © 2011-2022 走看看