zoukankan      html  css  js  c++  java
  • 【GDOI 2011 DAY2 T3】零什么的最讨厌了 (快速求阶乘、中国剩余定理)

    问题描述:

    林记在做数学习题的时候,经常遇到这种情况:苦思冥想了很久终于把问题解出来,结果发现答案是0,久而久之林记在得到习题答案是0的时候就没有了做出一道难题的成就感。于是林记决定:以后出题,答案一定不能是0,例如求n!最低位非零数这样的习题就很不错了。

    现在林记提出了一个更难一点的问题:求n!在K进制下的最低位非零数。其中K符合一些特殊的条件:K是由若干个互不相同的质数相乘得出来的,例如K=2,3,5,6,7,10……

    输入格式:

    首先输入的第一行是一个整数Q,表示询问的个数。

    接下来是Q个询问,每个询问有两行组成,第一行首先是一个整数nk,然后紧跟着nk个正整数:m1m2,……mnk,则K为所有mi的乘积,输入保证mi是有若干个互不相同的质数相乘得出来的。接下来一行给出一个整数n

    输出格式:

    对于每个询问,如果K不符合题目限制,则输出“I hate zero.”(不用加双引号)。否则输出K进制下n!的最低位非零数。

    输入样例:

    输出样例:

    3

    1 17

    9

    1 6

    49

    1 93

    16

    15

    2

    78

    数据范围:

    对于10%的数据满足:n10K100

    对于50%的数据满足:n100000K100

    对于100%的数据满足:n1015K1015mi106Q20

    【分析】

      快速求阶乘大法!!

      下面某步还用到 威尔逊定理 (p-1)!%p=p-1...... (也可以预处理出来的)

      把m分解质因数,对于质数p单独求n!=p^a+b的a的值和b%p的值(logn递归搞定),然后用中国剩余定理合并起来。

      

      long long的乘积会爆,所以...要用那个不断乘2的方法:

      

    LL mul(LL x,LL y,LL p)
    {
    	if(x==0||y==0) return 0;
    	LL now=x,yy=y,add=0;
    	while(yy>1)
    	{
    		if(yy%2!=0) add=(add+now)%p;
    		now=(now*2)%p;
    		yy/=2;
    	}
    	return (now+add)%p;
    }
    

    代码如下:

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 #include<cmath>
      8 using namespace std;
      9 #define Maxn 1000010
     10 #define INF 0xfffffff
     11 #define LL long long
     12 
     13 LL nk,m[Maxn],ml,K;
     14 LL n;
     15 LL prime[Maxn],pl;
     16 bool q[Maxn];
     17 LL mn;
     18 
     19 LL mymin(LL x,LL y) {return x<y?x:y;}
     20 
     21 void get_pri(LL mx)
     22 {
     23     pl=0;
     24     memset(q,1,sizeof(q));
     25     for(LL i=2;i<=mx;i++)
     26     {
     27         if(q[i]) prime[++pl]=i;
     28         for(int j=1;j<=pl;j++)
     29         {
     30             if(i*prime[j]>mx) break;
     31             q[i*prime[j]]=0;
     32             if(i%prime[j]==0) break;
     33         }
     34     }
     35 }
     36 
     37 bool div(LL mm)
     38 {
     39     for(LL i=1;prime[i]*prime[i]<=mm;i++) if(mm%prime[i]==0)
     40     {
     41         m[++ml]=prime[i];
     42         mm/=prime[i];
     43         while(mm%prime[i]==0) return 0;
     44     }
     45     if(mm!=1) m[++ml]=mm;
     46     return 1;
     47 }
     48 
     49 bool init()
     50 {
     51     ml=0;
     52     scanf("%lld",&nk);
     53     K=1;
     54     bool ok=1;
     55     for(int i=1;i<=nk;i++) 
     56     {
     57         LL mm;
     58         scanf("%lld",&mm);K*=mm;
     59         if(!div(mm)) ok=0;
     60     }
     61     sort(m+1,m+1+ml);
     62     for(LL i=2;i<=ml;i++) if(m[i]==m[i-1]) {ok=0;break;}
     63     scanf("%lld",&n);
     64     if(!ok) return 0;
     65     return 1;
     66 }
     67 
     68 LL f[Maxn];
     69 
     70 struct node{LL x,y;};
     71 node c[Maxn];
     72 
     73 node ffind(LL x,LL p)
     74 {
     75     node ans;
     76     if(x<p)
     77     {
     78         ans.x=0;
     79         ans.y=f[x];
     80         return ans;
     81     }
     82     ans.x=0;ans.y=1;
     83     node t=ffind(x/p,p);
     84     ans.x+=t.x; ans.y*=t.y;
     85     ans.y=(ans.y*f[x%p])%p;
     86     ans.x+=x/p;
     87     
     88     LL y=(((x/p)%2)==0)?1:p-1;
     89     ans.y=(ans.y*y)%p;
     90     
     91     return ans;
     92 }
     93 
     94 LL mul(LL x,LL y,LL p)
     95 {
     96     if(x==0||y==0) return 0;
     97     LL now=x,yy=y,add=0;
     98     while(yy>1)
     99     {
    100         if(yy%2!=0) add=(add+now)%p;
    101         now=(now*2)%p;
    102         yy/=2;
    103     }
    104     return (now+add)%p;
    105 }
    106 
    107 LL qpow(LL x,LL b,LL p)
    108 {
    109     LL ans=1;
    110     while(b)
    111     {
    112         if(b&1) ans=mul(ans,x,p);
    113         x=mul(x,x,p);
    114         b>>=1;
    115     }
    116     return ans;
    117 }
    118 
    119 LL d[Maxn];
    120 
    121 LL get_ans()
    122 {
    123     mn=c[1].x;
    124     for(LL i=2;i<=ml;i++) mn=mymin(mn,c[i].x);
    125     for(LL i=1;i<=ml;i++)
    126     {
    127         if(c[i].x>mn) {d[i]=0;continue;}
    128         LL bm=qpow(K/m[i],mn,m[i]);
    129         bm=qpow(bm,m[i]-2,m[i]);
    130         d[i]=mul(bm,c[i].y,m[i]);//(bm*c[i].y)%m[i];
    131     }
    132     LL ans=0;
    133     for(LL i=1;i<=ml;i++)
    134     {
    135         LL y=qpow(K/m[i],m[i]-2,m[i]);
    136         //ans=(ans+((K/m[i]*y)%K)*d[i])%K;
    137         ans=(ans+mul(mul(K/m[i],y,K),d[i],K))%K;
    138     }
    139     return ans;
    140 }
    141 
    142 int main()
    143 {
    144     get_pri(1000000);
    145     int T;
    146     scanf("%d",&T);
    147     while(T--)
    148     {
    149         if(!init()) {printf("I hate zero.
    ");continue;}
    150         for(LL i=1;i<=ml;i++)
    151         {
    152             f[0]=1;
    153             for(LL j=1;j<m[i];j++) f[j]=(f[j-1]*j)%m[i];
    154             c[i]=ffind(n,(LL)m[i]);
    155         }
    156         printf("%lld
    ",get_ans());
    157     }
    158     return 0;
    159 }
    View Code

    2016-09-04 19:37:26

  • 相关阅读:
    猜拳游戏GuessGame源码
    基于vitamio的网络电视直播源码
    EarthWarrior3D游戏ios源码
    类似material design的电影应用源码
    四季电台应用项目源码
    高仿一元云购IOS应用源码项目
    非常不错的点餐系统应用ios源码完整版
    仿哔哩哔哩应用客户端Android版源码项目
    《你最美》换发型应用源码
    最新win7系统64位和32位系统Ghost装机稳定版下载
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5840039.html
Copyright © 2011-2022 走看看