【bzoj题解】2186 莎拉公主的困惑

题目传送门

题意:求\([1,n!]\)中与\(m!\)互质的数的个数,对质数\(R\)取模,\(n\geq m\)。

答案应该等于\(\frac{n!}{m!}\phi(m!)=\frac{n!}{m!}m!\prod_{p|m!}\frac{p-1}{p}=n!\frac{\prod_{p\leq m}\,p-1}{\prod_{p\leq m}\,p}\)。

这里\(p\)为小于等于\(m\)的质数。

所以我们处理出阶乘,以及质数的乘积和对\(R\)的逆元就能得出答案。

你真的这么想?

naive!simple!

如果\(n\geq R\),答案一定为\(0\)吗?

可以看看这组数据:

1 3
4 3

答案为\(2\),因为\(8\,mod\,3=2\)。

但是\(4!\frac{1\cdot 2}{2\cdot 3}\)呢?\(4!=24\),而\(24\,mod\,3=0\),但是答案非\(0\)。

正确的做法是什么?

当\(n\geq R\)时,如果\(m\geq R\)的话,\(n!\)中的因子\(R\)就有可能被分母消掉,我们应该要对\(n\geq R\)的\(n!\)消掉一个\(R\),对\(m\geq R\)的分母也消掉一个\(R\)。

这样就不会有问题了。

代码如下:

 1 #include<cstdio>
 2 #define F(i,a,b) for(int i=(a);i<=(b);++i)
 3 #define F2(i,a,b) for(int i=(a);i<(b);++i)
 4 int T,Mod,n,m;
 5 int primes[664580], pnum=0;
 6 bool isn_prime[10000001];
 7 int pi[664580],inv[10000001];
 8 int in[664580],fct[10000001];
 9 int pos[10000001];
10 void init(){
11     isn_prime[0]=isn_prime[1]=1;
12     F(i,2,10000000){
13         if(!isn_prime[i]) primes[++pnum]=i;
14         for(int j=1;j<=pnum&&primes[j]*i<=10000000;++j){
15             isn_prime[primes[j]*i]=1;
16             if(i%primes[j]==0) break;
17         }
18     }
19     inv[1]=1; for(int i=2;i<Mod&&i<=10000000;++i)
20         inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
21     pi[0]=1; F(i,1,pnum) pi[i]=1ll*pi[i-1]*(primes[i]-1)%Mod;
22     in[0]=1; F(i,1,pnum) if(primes[i]!=Mod) in[i]=1ll*in[i-1]*inv[primes[i]%Mod]%Mod; else in[i]=in[i-1];
23     fct[0]=1; F(i,1,10000000) if(i!=Mod) fct[i]=1ll*fct[i-1]*i%Mod; else fct[i]=fct[i-1];
24     F(i,2,10000000) if(isn_prime[i]) pos[i]=pos[i-1]; else pos[i]=pos[i-1]+1;
25 }
26 int main(){
27     scanf("%d%d",&T,&Mod);
28     init();
29     while(T--){
30         scanf("%d%d",&n,&m);
31         if(n>=Mod&&m<Mod) puts("0");
32         else printf("%d\n",1ll*fct[n]*pi[pos[m]]%Mod*in[pos[m]]%Mod);
33     }
34     return 0;
35 }

原文地址:https://www.cnblogs.com/PinkRabbit/p/8166797.html

时间: 2024-11-10 17:57:50

【bzoj题解】2186 莎拉公主的困惑的相关文章

【BZOJ】2186 沙拉公主的困惑

一道非常有价值的题. [解析1]欧几里德算法求乘法逆元,前缀和 [Analysis]O(T n log n). [Sum] ①int运算,如果会超出界,第一个数前要加上(LL)即类型转换. ②gcd不变的欧几里德定理:可以是加,也可以是减. [Code] /************************************************************** Problem: 2186 User: y20070316 Language: C++ Result: Accept

BZOJ:2186: [Sdoi2008]沙拉公主的困惑

问题:可能逆元不存在吗? 题解: Gcd(a,b)==Gcd(b,a-b); 从数据范围可以看出应该求M!的欧拉函数: 然后通过Gcd转化过去 一开始没想到 #include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long Lint; const int maxT=20000; const int maxn=10000009; int T,r; int

【题解】SDOI2008莎拉公主的困惑

挺有趣的恩:洛谷P2155 在纸上打打草稿,写出n!个数,从先往后,遇到不互质的就筛掉--发现一个奇妙的性质!:筛掉的次数.顺序好像是周期性出现的呢~ 而且更加妙妙的是,好像还是m!一轮..那么因为n!一定能被m!整除,所以问题转变为:(n!\m! - 有多少个循环节)*(φ(m)). 接下来,φ(m) = m!*(1 - 1/p1)*(1 - 1/p2)...任务就只剩下打出阶乘表&逆元啦.离线的处理会快很多. #include <bits/stdc++.h> using names

【NOI题解】【bzoj题解】NOI2008 bzoj1063 道路设计

@ACMLCZH学长出的毒瘤题T3.再也不是"善良"的出题人了. 题意:bzoj. 题解: 经典的树形DP题目,屡见不鲜了,然而我还是没有写出来. 这一类的题目有很多,例如这里的C题. 主要套路是把对儿子的枚举变成一个类似背包的转移方式,实现降复杂度. 需要注意的是某一个地方的DP值不能直接拿来判断是否有解,例如mod=1时,DP值全为0就没法判断了. 这里比较骚的操作是把mod的倍数变成mod,而0变成0,这样就不会漏判. #include<bits/stdc++.h>

【bzoj题解】1012 最大数

题目描述 现在请求你维护一个数列,要求提供以下两种操作:1.查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2.插入操作.语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾.限制:n是非负整数并且在长整范围内.注意:初始时数列是空的,没有一个数. 输入 第一行两个整数,M和D,其中M表示操作的个数(M <= 200,0

【BZOJ1095】捉迷藏(动态点分治)

[BZOJ1095]捉迷藏(动态点分治) 题面 BZOJ 题解 动态点分治板子题 假设,不考虑动态点分治 我们来想怎么打暴力: \(O(n)DP\)求树的最长链 一定都会.不想解释了 所以,利用上面的思想 对于每个点,维护子树到他的最长链 以及子树到他的次长链 把这两个玩意拼起来就可能是答案啦 所以,每个点维护两个堆 一个维护子树上的点到他的距离 一个维护所有子树的前面那个堆的最大值 也就是所以子树中,到达当前点的最长链 再在全局维护一个堆 记录每个点最长链和次长链的和 这样子就可以动态的维护了

【BZOJ1899】午餐(动态规划)

[BZOJ1899]午餐(动态规划) 题面 BZOJ 题解 我太弱了 这种\(dp\)完全做不动.. 首先,感性理解一些 如果所有人都要早点走, 那么,吃饭时间长的就先吃 吃饭时间短的就晚点吃 所以,按照吃饭时间排序 我们不难得出一个每个人吃完饭的时间 之和前面所有人的打饭的时间和有关 所以 \(f[i][j][k]\)表示当前做到第\(i\)个人,第一列,第二列前面的人的打饭时间之和分别为\(j,k\)时,最后一个人吃完饭的最小时间 因为人的顺序我们是知道的 所以\(j+k\)是一个定值,是所

【BZOJ1212】L语言(AC自动机)

[BZOJ1212]L语言(AC自动机) 题面 BZOJ 题解 很自然的,既然要匹配单词,那就全部都丢到\(AC\)自动机里面去 现在想想怎么匹配 先是\(AC\)自动机正常的匹配 如果此时这个位置能够匹配上一个串 我们就需要判断一下这个串覆盖到这个文本串中 它的前一位是否恰好被覆盖 如果有的话 我们也不能直接计算 因为可能是其他不同的串拼起来的 所以,就开一个数组差分 表示当前位置可以匹配 最后,对于每个文本串 从前往后扫一遍差分数组 直到有\(0\)的地方就直接输出就行啦 #include<

【BZOJ3671】【NOI2014】随机数据生成器(贪心)

[BZOJ3671][NOI2014]随机数据生成器(贪心) 题面 BZOJ 题解 前面的模拟 真的就是语文阅读理解题目 理解清楚题目意思 然后就会发现要求的就是一个贪心 从小往大枚举,检查当前数能不能选 如果能选 就会限制其他行的左右能够到达的范围 暴力修改一下 然后就很愉快的\(AC\)了 这题别的不卡 卡空间,卡格式 我也是醉了 #include<iostream> #include<cstdio> #include<cstdlib> #include<cs