mod的一些性质
(a mod n) (b mod n)=(ab) mod n
((a mod n)(b mod n)) mod n=(ab) mod n
如果a≡b(mod m),x≡y(mod m),则a+x≡b+y(mod m)。
如果a≡b(mod m),x≡y(mod m),则ax≡by(mod m)。
如果ac≡bc(mod m),且c和m互质,则a≡b(mod m) (就是说同余式两边可以同时除以一个和模数互质的数)。
川大新生杯——模板筛
lglg最近爱上了炒股,他想在股票市场内买一些股票。
现在有编号为1,2,3,...,100000000的100000000支股票,每个股票的价值等于其编号的阶乘(例如编号为5的股票的价值就是120)。
lglg是一个很挑剔的人,他只喜欢编号为质数的股票,但他很有钱,因此他希望买下所有编号小于等于N(1<=N<=1e8)并且编号为质数的股票,请你帮他算一算这些股票的价值之和。
由于价值和很大,他希望你能告诉他价值之和对P(1e3<=P<=1e5)取模后的值。
输入描述:
输入包含多组数据 第一行是一个正整数 T(1<=T<=1000),代表数据的组数。每组数据只有一行,包含两个正整数 N 和 P 数字之间用空格隔开,其代表的含义及范围已在题面中给出。
输出描述:
每组数据输出一行,表示lglg希望买下的所有股票的价值之和对P取模后的值
示例1
输入
2 5 1001 20 1001
输出
128 86
欧拉筛和mod的运用能让跑起来贼快。
mod:
1、阶乘的时候比mod的数大了肯定就永远是零了,不用算了,所以比P大的肯定是零了,阶乘和对p取余,那阶乘对P取余岂不是更满足了,所以欧拉筛只要筛1e5以下的就行,不用1e8
2、每个组数据只算算一遍阶乘,遇到素数就算和,不是素数不算,但阶乘(和mod)还在跑,循环结尾到n,要是到mod的p了也不用跑了,后面必定已经都零了
欧拉筛:打表从2筛到需要的最大,每个合数被它的最小质因子筛出去,prime【0】用来存储一共多少,对于visit[i*prime[j]] = 1 的解释: 这里不是用i的倍数来消去合数,而是把 prime里面纪录的素数,升序来当做要消去合数的最小素因子。
打表观察来理解 :发现i在消去合数中的作用是当做倍数的。
对于 i%prime[j] == 0 就break的解释 :当 i是prime[j]的倍数时,i = kprime[j],如果继续运算 j+1,i * prime[j+1] = prime[j] * k prime[j+1],这里prime[j]是最小的素因子,当i = k * prime[j+1]时会重复,所以才跳出循环。
举个例子 :i = 8 ,j = 1,prime[j] = 2,如果不跳出循环,prime[j+1] = 3,8 * 3 = 2 * 4 * 3 = 2 * 12,在i = 12时会计算。因为欧拉筛法的原理便是通过最小素因子来消除。
————————————————
版权声明:本文为CSDN博主「彤云望月」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39763472/article/details/82428602
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; bool visit[100010]; int prime[100010]; void oulashai() { memset(visit,0,sizeof(visit)); for (int i=2;i<=100000;i++) { if (!visit[i]) prime[++prime[0]]=i; for (int j=1;j<=prime[0] and i*prime[j]<=100000;j++) { visit[i*prime[j]]=1; if (i%prime[j]==0) break; } } } int main() { // freopen("test.in","r",stdin); // freopen("test.out","w",stdout); int t,n,p; oulashai(); cin>>t; for (int i=1;i<=t;i++) { long long sum=0,jc=1; scanf("%d%d",&n,&p); for (int j=2;j<=min(n,p);j++) { jc=(jc*j)%p; if (!visit[j]) sum=(sum+jc)%p; } printf("%lld\n",sum); } }