【BZOJ】2186 沙拉公主的困惑

一道非常有价值的题。

【解析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时有用。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-01 05:44:53

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

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

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

大视野2186: 沙拉公主的困惑(求逆元)

2186: [Sdoi2008]沙拉公主的困惑 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 2616  Solved: 880 [Submit][Status][Discuss] Description 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票.房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量.现在,请你帮助沙拉公主解决这个问题,由于可能张

bzoj 2186 [Sdoi2008]沙拉公主的困惑 欧拉函数

bzoj 2186 [Sdoi2008]沙拉公主的困惑 题意: 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票.房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量.现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可.R是一个质数. 限制: 数据组数T:1 <= T <= 10000 R <= 1e9+10 1 <= N,M <=10000000

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

Description 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票.房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量.现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可.R是一个质数. Input 第一行为两个整数T,R.R<=10^9+10,T<=10000,表示该组中测试数据数目,R为模后面T行,每行一对整数N,M,见题目描述 m<=n Outp

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

2186: [Sdoi2008]沙拉公主的困惑 Description 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票.房地产第一 大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量.现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可. R是一个质数. Input 第一行为两个整数T,R.R<=10^9+10,T<=10000,表示该组中测试数据数目,R为模后面T行,每行

BZOJ 2186: [Sdoi2008]沙拉公主的困惑 (逆元的应用)

传送门 Problem 2186. – [Sdoi2008]沙拉公主的困惑 2186: [Sdoi2008]沙拉公主的困惑 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 3058  Solved: 1040[Submit][Status][Discuss] Description 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票.房地产第一大户沙拉公主决定预测一下大

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

2186: [Sdoi2008]沙拉公主的困惑 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 3303  Solved: 1129[Submit][Status][Discuss] Description 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票.房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量.现在,请你帮助沙拉公主解决这个问题,由于可能张数

bzoj2186【SDOI2008】沙拉公主的困惑

2186: [Sdoi2008]沙拉公主的困惑 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 2363  Solved: 779 [Submit][Status][Discuss] Description 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票.房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量.现在,请你帮助沙拉公主解决这个问题,由于可能张

bzoj2186: [Sdoi2008]沙拉公主的困惑

线性求逆元后好神的数论啊.... #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #define rep(i,s,t) for(register int i=s;i<=t;i++) #define dwn(i,s,t) for(register int i=s;i>=t;i--) #define clr(x,c