【学术篇】SDOI2008 沙拉公主的困惑

传送门!

题目在里…

题目大意?

难道不是说的很清楚了么OvO
求n!中与m!互质的数的个数..

题目分析.

显然的数论… 所以就是化式子呗..
一个很显然的性质就是如果 gcd(a,b)=1 ,那么 gcd(a+kb,b)=1
而题目中说了 mn , ∴ m!|n!
于是我们只需要计算 m! 中与 m! 互质的数的个数,然后乘以 n!m! 即可..
我们发现上面加粗的这一坨就是 φ(m!) 嘛…
所以 ans=φ(m!)n!m!
又有 φ(x)=xni(11pi) 其中 pi 表示x的质因数…
m!=12...m , 所以 m! 的质因数很显然就是不大于 m 的质数…
然后带入上式约掉m!就有了 ans=n!nipi1pi (其中 pim pi 为质数)…
由于多组询问, 而且内存开了256MB不是 所以我们要预处理… 不然会T…
由于上式, 我们要预处理的东西有:
- 筛素数(简单欧拉筛)
- 阶乘(顺着乘一遍取模就行了)
- 逆元(要递推求出所有数的哦) (所以最好用 O(n) 的, 不会的话直接看代码就行了 百度一下一堆详细讲解OvO)
- muli=nipi1pi 这一坨东西…(不大于 m 的质数pi们的 (11pi) 的乘积…)
然后处理这一坨的时候也很容易…递推即可.. 显然, 我们有
1. 当 i 是质数时, muli=muli1i1i
2. 否则 muli=muli1 即可…
这样就做完了.

实现代码:

#include <cstdio>
typedef long long LL;
const int X=1e7+3;
inline int gn(int a=0,char c=0){
    for(;c<48||c>57;c=getchar());
    for(;c>47&&c<58;c=getchar())
        a=a*10+c-48; return a;
}
int inv[X],fac[X],eu[X],mul[X],pri[X/10],tot;
bool notp[X]; int T,R,M,N;
void prime(){
    notp[1]=1;
    for(int i=2;i<X;++i){
        if(!notp[i])pri[++tot]=i;
        for(int j=1;j<=tot&&i*pri[j]<=1e7;++j){
            notp[i*pri[j]]=1; if(i%pri[j]==0) break;
        }
    }
}
void calcinv(){
    inv[1]=1;
    for(int i=2;i<X;++i){
        inv[i]=(LL)(R-R/i)*inv[R%i]%R;
        if(inv[i]<0) inv[i]+=R;
    }
}
void calcfac(){
    fac[1]=1;
    for(int i=2;i<X;++i)
        fac[i]=(LL)fac[i-1]*i%R;
}
void calcmul(){
    mul[1]=1;
    for(int i=2;i<X;++i)
        if(!notp[i]) mul[i]=(LL)mul[i-1]*(i-1)%R*inv[i]%R;
        else mul[i]=mul[i-1];
}
int main(){
    T=gn(),R=gn();
    prime(); calcinv(); calcfac(); calcmul();
    while(T--){
        N=gn(),M=gn();
        printf("%d\n",(int)((LL)fac[N]*mul[M]%R));
    }
}

注意事项~

  1. 做乘法的时候要转long long,(当然你要是全用long long算当我没说
  2. 预处理的时候1的值作为边界值给出, 循环要从2开始
  3. 每一步都记得取模
  4. 输出的时候记得换行而不是空格(我是不是暴露了什么←_←

完结撒花

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值