【GDOI 2011 DAY2 T3】零什么的最讨厌了 (快速求阶乘、中国剩余定理)

问题描述:

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

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

输入格式:

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

接下来是Q个询问,每个询问有两行组成,第一行首先是一个整数nk,然后紧跟着nk个正整数:m1,m2,……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%的数据满足:n≤10,K≤100

对于50%的数据满足:n≤100000,K≤100

对于100%的数据满足:n≤1015,K≤1015,mi≤106,Q≤20

【分析】

  快速求阶乘大法!!

  下面某步还用到 威尔逊定理 (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.\n");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\n",get_ans());
157     }
158     return 0;
159 }

2016-09-04 19:37:26

时间: 2024-10-12 12:50:40

【GDOI 2011 DAY2 T3】零什么的最讨厌了 (快速求阶乘、中国剩余定理)的相关文章

1130: 零起点学算法37——求阶乘

1130: 零起点学算法37--求阶乘 Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitted: 2109  Accepted: 1328[Submit][Status][Web Board] Description 输入一个正整数n,计算它的阶乘 Input 输入一个正整数n(n<=10)(多组数据) Output 输出n的阶乘(每组数据一行) Sample Input 3 Sample Output 6

1131: 零起点学算法38——求阶乘和

1131: 零起点学算法38--求阶乘和 Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitted: 2719  Accepted: 1736[Submit][Status][Web Board] Description 输入一个正整数n(n<=10),计算 S=1!+2!+3!+...+n! Input 输入一个正整数n(n<=10)(多组数据) Output 输出S(每组数据一行) Sample Inpu

light_oj 1138 求阶乘后导零的个数

light_oj 1138  求阶乘后导零的个数 N - Trailing Zeroes (III) Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Practice LightOJ 1138 Description You task is to find minimal natural number N, so that N! contains exactly Q 

【NOIP之旅】NOIP2014 day2 T3 解方程

3.解方程 (equation.cpp/c/pas) [问题描述] 已知多项式方程: 求这个方程在[1, m]内的整数解(n和m均为正整数).   [输入] 输入文件名为equation.in. 输入共n+2行. 第一行包含2个整数n.m,每两个整数之间用一个空格隔开. 接下来的n+1行每行包含一个整数,依次为a0,a1,a2,……,an. [输出] 输出文件名为equation.out. 第一行输出方程在[1, m]内的整数解的个数. 接下来每行一个整数,按照从小到大的顺序依次输出方程在[1,

HNOI2016 Day2 T3 大数(BZOJ4542)

莫队算法 今天为了做这道题先去学了莫队算法,然后A掉了莫队算法的入门题目——小Z的袜子. 考场上面我傻逼的打了一个高精度,华丽丢掉暴力分.然而我发现只需要取个模就可以了,考场上傻了. 学完莫队算法之后,发现这道题其实就是一个裸题. 一开始依然是莫队算法的方式,按左端点所在块的编号为第一关键字,右端点编号为第二关键字排序, 考虑先暴力处理每个块的第一组询问,之后可以发现我们只需要微调一下区间的左右端点就可以了.比如说:我上次处理了1 5,那么1 6就可以只把6加进去就可以了:如果这一次是2 6,那

NOIp 2011 Day2 解题报告

1.计算系数 本人比较耿直,没有想到递推的组合数公式,而是用了快速幂求逆元. 复杂度O(Klog10007) 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 //variable// 9 int a,b,k,n,m,mod=10007; 10

2012Noip提高组Day2 T3 疫情控制

题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点.但特别要注意的是,首都是不能建立检查点的. 现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队.一支军队可以在有道路连接的城市间移动

NOIP2017 Day2 T3 列队(treap)

可以直接用treap上大模拟...n+1个treap维护n行的前m-1个点和最后一列. 需要支持删除一个点或者一段区间,而空间并不支持存下所有的点的时候,可以用一个点代替一个区间,记录区间首项的值和区间长度,这样每次查询某个点x的时候就可以用x在某个点y代表的区间里的rank来得到x的值,然后把x删去的时候,就把y这个区间从$[l,r]$拆分成$[l,x-1]$和$[x+1,r]$,重新加入. 类似的题有NOI超级钢琴 #include<iostream> #include<cstrin

零基础学python-16.1 作用域快速入门

这一章节我们来聊聊作用域基础 python在创建.改变或者查找变量都是在所谓的命名空间中进行,作用域指的就是命名空间 简单的说:就是这个变量可以被访问的范围 我们举一个比较容易理解的例子--函数 >>> def test(): x=1 print(x) >>> x Traceback (most recent call last): File "<pyshell#10>", line 1, in <module> x Name