bzoj2186 莎拉公主的困惑【线性筛+欧拉函数+逆元】

本文介绍了一种高效求解模意义下阶乘与欧拉函数相关问题的方法,通过线性筛法预处理素数及其逆元,实现了快速计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2186

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<ctype.h>
#include<time.h>
#include<stack>
#include<queue>
#include<bitset>
#include<set>
#include<map>
#include<vector>
#include<sstream>
using namespace std;
typedef long long ll;
void fre(){freopen("in.txt","r",stdin);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define zero(a) fabs(a)<eps
#define equal(a,b) zero(a-b)
const int pi=acos(-1);
double e=2.718281828;
const int N=1000000;
int t,mod,n,m,cnt;
int fac[N+5],ine[N+5],x[500005],ans[N+5];
bool flag[N+5];

void exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
    x=1;
    y=0;
    return;
    }
    exgcd(b,a%b,x,y);
    int t=x;x=y;y=t-a/b*y;
}

int getine(int t)
{
    int x,y;
    exgcd(t,mod,x,y);
    return (x%mod+mod)%mod;
}

void init()
{
    fac[1]=1;
    for(int i=2;i<=N;i++)
        fac[i]=(ll)fac[i-1]*i%mod;
    ine[1]=1;
    for(int i=2;i<=N;i++)
    {
        if(!flag[i])
            x[++cnt]=i,ine[i]=getine(i);
        for(int j=1;x[j]*i<=N&&j<=cnt;j++)
        {
            flag[x[j]*i]=1;
            //ine[pri[j]*i]=(ll)ine[pri[j]]*ine[i]%R;
            if(i%x[j]==0)break;
        }
    }
    ans[1]=1;
    for(int i=2;i<=N;i++)
    {
        ans[i]=ans[i-1];
        if(!flag[i])
            ans[i]=(ll)ans[i]*(i-1)%mod*ine[i]%mod;
    }
}

int main()
{
    scanf("%d%d",&t,&mod);
    init();
    while(t--)
    {
        scanf("%d%d",&n,&m);
        printf("%I64d\n",(ll)fac[n]*ans[m]%mod);
    }
    return 0;
}

分析:题目要求[1,n!]里与m!互质的数的个数,[1,m!]中与m!互质的数有 Oular(m!) 个,对于每个互质的

数,如果我们给他都加上M!,仍然和m!互质,即求 Oular(m!)n!/m! , 根据欧拉函数的性质,可以把

Oular(m!) 化简为 m!((p1)/p) ,p为m!的质因数,就变成了求 n!((p1)/p) ,求到此就很清晰了,

预处理线性筛出[1,10000000]的素数,求出逆元,同时求出阶乘取模,随便搞搞就出来了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值