一道很有价值的题。



【解析1】欧几里德算法求乘法逆元,前缀和



[Analysis]O(T n log n)。

[Sum]

①int运算。假设会超出界,第一个数前要加上(LL)即类型转换。

②gcd不变的欧几里德定理:能够是加。也能够是减。



[Code]

/**************************************************************
Problem: 2186
User: y20070316
Language: C++
Result: Accepted
Time:6496 ms
Memory:157056 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std; typedef long long LL;
const int N=10000001; int p[N],v[N],inv[N]; //screen
int pre[N]; //Prefix n!
int cas,r,n,m; //Basic
int x,y; //Exgcd void exgcd(int i,int j)
{
if (!j) {x=1,y=0;return;}
exgcd(j,i%j);
int x_=y,y_=x-(i/j)*y;
x=x_,y=y_;
} int main(void)
{
scanf("%d%d",&cas,&r); for (int i=2;i<N;i++)
{
if (!v[i])
{
p[++p[0]]=i;
exgcd(i,r),inv[i]=x%r;
}
for (int j=1;j<=p[0];j++)
{
if (i*p[j]>=N) break;
v[i*p[j]]=1;
if (i%p[j]==0) break;
}
} pre[0]=1;
for (int i=1;i<N;i++)
pre[i]=(LL)pre[i-1]*i%r; inv[1]=1;
for (int i=2;i<N;i++)
if (!inv[i])
inv[i]=inv[i-1];
else
{
inv[i]=(LL)inv[i]*(i-1)%r;
inv[i]=(LL)inv[i]*inv[i-1]%r;
} for (int cc=1;cc<=cas;cc++)
{
scanf("%d%d",&n,&m);
printf("%d\n",((LL)pre[n]*inv[m]%r+r)%r);
} return 0;
}</span>

【解析2】递推求乘法逆元,前缀和



[Analysis]O(Tn)

性质:关于Mod M作用下i的逆元inv[i]=-(M/i)*inv[M%i]。

证明:

令a=M/i,b=M%i,

∴M=ai+b。

∴inv[i] = -a * inv[b]。

同余式两边同一时候乘上i。得:

i * inv[i]

= -ai * inv[b]

= (b-M) * inv[b]

= b*inv[b]

= 1 (mod M)

∴inv[i]为在Mod M下i的逆元,证毕。

O(n)求法比直接求全部素数的逆元还慢一些...

[Code]

/**************************************************************
Problem: 2186
User: y20070316
Language: C++
Result: Accepted
Time:7700 ms
Memory:196116 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std; typedef long long LL;
const int N=10000001; int p[N],v[N]; //screen
int inv[N],sinv[N]; //Mutiplicative Inverse
int pre[N]; //Prefix n!
int cas,r,n,m; //Basic int main(void)
{
scanf("%d%d",&cas,&r); for (int i=2;i<N;i++)
{
if (!v[i]) p[++p[0]]=i;
for (int j=1;j<=p[0];j++)
{
if (i*p[j]>=N) break;
v[i*p[j]]=1;
if (i%p[j]==0) break;
}
} pre[0]=1;
for (int i=1;i<N;i++)
pre[i]=(LL)pre[i-1]*i%r; inv[1]=1;
for (int i=2;i<N;i++)
inv[i]=(LL)(r-r/i)*inv[r%i]%r; sinv[1]=1;
for (int i=2;i<N;i++)
{
sinv[i]=sinv[i-1];
if (!v[i])
{
sinv[i]=(LL)sinv[i]*(i-1)%r;
sinv[i]=(LL)sinv[i]*inv[i]%r;
}
} for (int cc=1;cc<=cas;cc++)
{
scanf("%d%d",&n,&m);
printf("%d\n",((LL)pre[n]*sinv[m]%r+r)%r);
} return 0;
}</span>

以下是做这道题时做的一些笔记:

1.阶乘的乘除

①直接计算。

②分解质因数。

假设有取余,用①方便。

假设要写高精度,用②方便。

2、欧拉函数的求法

例:求fai(60)

①分解质因数正规求法

60=2^2 * 3^1 * 5^1。

∴fai(60)=60 * (1-1/2) * (1-1/3) * (1-1/5) = 16。

②依据①的还有一种求法

fai(60)= (1 * 2^1) * (2*3^0) * (4*5^0)= 16。

③积性函数的解法:可结合欧拉筛法达到O(n)求出全部。

fai(60) = fai(2^2) * fai(3^1) * fai(5^1) = 16。

3、乘法逆元(mutiplicative inverse)

(1)什么是乘法逆元?

群G中随意一个元素a,都在G中有唯一的逆元a',s.t. aa'=a'a=e,e为单位元。

例:求4关于1模7的逆元,即求关于X的方程 4X ≡1 (mod 7)。

(2)怎么求乘法逆元?

在求乘法逆元aa'=b(mod c)前,要满足(a,c)=1即(a,c)互质。

①同余方程 --> 不定方程 --> exgcd。

单个。O(log n)。

②欧拉定理

依据欧拉定理,当a与P互质时,a ^ fai(P) = 1 (mod P)。

∴a * a^(fai(P)-1) =1 (mod P)。

在mod P意义下a的乘法逆元a' = a^(fai(P)-1)。

特别的,当P为质数时,a' = a^(P-2)。

单个,O(log fai(P)-1)。

③积性函数

乘法逆元是积性函数,能够线性筛(screen)。

对于素数考虑以上两种方法哪种好。

全部。O(log n)或者O(fai(P)-1),一般来说用①。

④递推法。 全部,O(n)。

关于递推法。见:

http://blog.csdn.net/whyorwhnt/article/details/19169035。

(3)一个经典的问题:求(a/b) mod p。

性质:设b'为b的逆元,即:b'b=1(mod p),那么 a/b = a*b' (mod p)。

证:

∵b'b=1(mod p)

∴b'b=1+px即b'=(1+px)/b。

∴a*b'=a*(1+px)/b=a*(1+0)/b(mod p)=a/b (mod p),证毕。

这个性质在a变求和边取模,然后求(a/b) mod p时实用。

【BZOJ】2186 沙拉公主的困惑的更多相关文章

  1. BZOJ 2186 沙拉公主的困惑

    2186: [Sdoi2008]沙拉公主的困惑 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 3397  Solved: 1164 [Submit] ...

  2. BZOJ 2186 沙拉公主的困惑(预处理逆元+欧拉函数)

    题意:求1-n!里与m!互质的数有多少?(m<=n<=1e6). 因为n!%m!=0,所以题目实际上求的是phi(m!)*n!/m!. 预处理出这些素数的逆元和阶乘的模即可. # incl ...

  3. Bzoj 2186: [Sdoi2008]沙拉公主的困惑 乘法逆元,线性筛,欧拉函数,数论

    2186: [Sdoi2008]沙拉公主的困惑 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 2560  Solved: 857[Submit][St ...

  4. 数学(逆元):BZOJ 2186: [Sdoi2008]沙拉公主的困惑

    2186: [Sdoi2008]沙拉公主的困惑 Description 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞 ...

  5. 【BZOJ 2186】 2186: [Sdoi2008]沙拉公主的困惑 (欧拉筛,线性求逆元)

    2186: [Sdoi2008]沙拉公主的困惑 Description 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞 ...

  6. BZOJ-2186 沙拉公主的困惑 线性筛(筛筛筛)+线性推逆元

    2186: [Sdoi2008]沙拉公主的困惑 Time Limit: 10 Sec Memory Limit: 259 MB Submit: 2417 Solved: 803 [Submit][St ...

  7. 【bzoj2186】[Sdoi2008]沙拉公主的困惑

    2186: [Sdoi2008]沙拉公主的困惑 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 3303  Solved: 1129[Submit][S ...

  8. 【BZOJ2186】沙拉公主的困惑(数论)

    [BZOJ2186]沙拉公主的困惑(数论) 题面 BZOJ 题解 考虑答案是啥 先假设\(n=m\) 现在求的就是\(\varphi(m!)\) 但是现在\(n!\)是\(m!\)的若干倍 我们知道 ...

  9. BZOJ2186: [Sdoi2008]沙拉公主的困惑(求[1,N!]与M!互素的个数)(线性筛)

    2186: [Sdoi2008]沙拉公主的困惑 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 6103  Solved: 2060[Submit][S ...

随机推荐

  1. 【Mybatis】未封装返回结果的字段自己返回值的问题

    在spring boot中使用mybatis过程中,发现有个实体的时间字段未在mapper方法执行完的封装结果中进行封装,但是却有值返回. 如下展示问题: 实体如下: package com.sxd. ...

  2. 如何把自己的代码发布到npmjs(npm publish)

    来源: https://www.cnblogs.com/calamus/p/8384318.html

  3. ElasticSearch的Rest的访问方式查询总量

    由于安装ElasticSearch插件会影响ES的性能,所以会尽量减少ES的插件安装 可以通过ElasticSearch-Sql插件 然后将生成的执行参数拷贝 { "query": ...

  4. RedHat虚拟机相关操作

    在VM虚拟机中安装完Redhat系统之后 如果需要用secureCRT连接linux系统的话 操作步骤如下: 1.进入linux系统,在终端输入ifconfig(注意,不是windows的ipconf ...

  5. Datatable和实体还有实体集List的差别与转化

    机房收费系统大家想必不是做完.就是已经在手上了,在一開始做的时候就明白规定.我们必须用实体.而不能使Datatable,由于说是Datatable直接面向了数据库,当时不是非常明白,于是也没有再深究, ...

  6. Angular 学习笔记——$http

    <!DOCTYPE HTML> <html ng-app="myApp"> <head> <meta http-equiv="C ...

  7. Mac OSX下编译安装PostgreSQL

    原先使用的是官方提供的安装包,可是安装包会创建postgre这个用户.在登陆界面看的有点不爽,搜索了半天居然没有找到怎样在osx下编译安装的教程,并且假设是依照官方文档的编译安装办法一定会让你崩溃,本 ...

  8. DirectX 11游戏编程学习笔记之6: 第5章The Rendering Pipeline(渲染管线)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

  9. RFS 理解

    1.背景 网卡接收一个数据包的情况下,会经过三个阶段:   - 网卡产生硬件中断通知CPU有包到达 - 通过软中断处理此数据包 - 在用户态程序处理此数据包   在SMP体系下,这三个阶段有可能在3个 ...

  10. 借助backtrace和demangle实现异常类Exception

    C++的异常类是没有栈痕迹的,如果需要获取栈痕迹,需要使用以下函数: #include <execinfo.h> int backtrace(void **buffer, int size ...