洛谷 P2155 BZOJ 2186 codevs 2301 [SDOI2008]沙拉公主的困惑

题目描述

大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可。R是一个质数。//codevs这里有坑,R是合数

输入输出格式

输入格式:

第一行为两个整数T,R。R<=10^9+10,T<=10000,表示该组中测试数据数目,R为模 后面T行,每行一对整数N,M,见题目描述 m<=n

输出格式:

共T行,对于每一对N,M,输出1至N!中与M!素质的数的数量对R取模后的值

输入输出样例

输入样例#1:

1 11
4 2

输出样例#1:

1

数据范围:
对于100%的数据,1 < = N , M < = 10000000

解题思路

  http://www.cnblogs.com/yangyaojia/p/6434611.html

  http://blog.csdn.net/loi_dqs/article/details/50520309

吐槽

  这题一题能抵三题做了。

  不想被卡常就离线吧,筛法筛到最大的n即可,否则卡常、卡内存太严重了,我的好不容易洛谷ac,跑了6s。

  求逆元可以线性递推,也可以扩欧。

  popoqqq大神博客的代码(https://www.luogu.org/record/show?rid=2565704)、黄学长博客(https://www.luogu.org/record/show?rid=2565713)里线性递推逆元的代码都在洛谷爆零,不知为啥。

  我的代码离线int会溢出,估计是筛法出问题,还不够优化,于是递推求逆元的数组开不下了,就用扩欧吧。

  卡一波常1.3s跑完(BZOJ不开O2跑了2.9s)。

源代码

6s的,求逆元用线性递推(BZOJ TLE)

#include<cstdio>
#include<cstring>
#include<algorithm>
int T,R,n,m;
long long  jc[10000010]={0};//阶乘取模
long long inv[10000010]={0};//逆元
bool not_prime[10000010]={0};//筛子
long long ans[10000010]={0};//pi累乘

void init()
{
    inv[1]=1;
    for(int i=2;i<=10000000&&i<R;i++)
        inv[i]=(R-R/i)%R*inv[R%i]%R;
    ans[1]=1;jc[1]=1;
    for(int i=2;i<=10000000;i++)
    {
        jc[i]=jc[i-1]*i%R;
        if(!not_prime[i])
        {
            ans[i]=ans[i-1]*(i-1)%R*inv[i%R]%R;
            for(int j=i<<1;j<=10000000;j+=i)
                not_prime[j]=1;
        }
        else
            ans[i]=ans[i-1];
    }
}

int main()
{
    scanf("%d%d",&T,&R);
    init();
    while(T--)
    {
        scanf("%d%d",&n,&m);
        printf("%lld\n",(long long)(jc[n])*(long long)(ans[m])%R);
    }
    return 0;
}

1.3s的,求逆元用扩欧

#include<cstdio>
#include<algorithm>
int T,R,maxn=-1;
long long  jc[10000010]={0};//阶乘取模
//int inv[10000010]={0};//逆元
bool not_prime[10000010]={0};//筛子
long long ans[10000010]={0};//pi累乘
int n[10000010]={0},m[10000010]={0};

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;
}
inline int getine(int t)
{
    int x,y;
    exgcd(t,R,x,y);
    return (x%R+R)%R;
}//扩欧求逆元

inline void Read(int &in){
    static char ch;
    for(ch=getchar();ch>‘9‘||ch<‘0‘;ch=getchar()) ;
    for(in=0;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) in=in*10+ch-‘0‘;
}
void init()
{
    /*inv[1]=1;
    for(int i=2;i<=maxn&&i<R;i++)
        inv[i]=(R-R/i)%R*inv[R%i]%R;*///线性递推求逆元
    ans[1]=1;jc[1]=1;
    for(int i=2;i<=maxn;i++)
    {
        jc[i]=jc[i-1]*i%R;
        if(!not_prime[i])
        {
            ans[i]=ans[i-1]*(i-1)%R*getine(i%R)%R;
            for(int j=i<<1;j<=maxn;j+=i)
                not_prime[j]=1;
        }
        else
            ans[i]=ans[i-1];
    }
}

int main()
{
    Read(T);Read(R);
    for(register int i=1;i<=T;i++)
         Read(n[i]),Read(m[i]),maxn=std::max(maxn,n[i]);
    init();
    for(register int i=1;i<=T;i++)
        printf("%lld\n",jc[n[i]]*ans[m[i]]%R);
    return 0;
}

洛谷记录里最优的代码,用户ID小小莫。Orz,洛谷跑了0.9s,BZOJ不开O2跑了2.6s,素数筛法值得学习。

#include <cstdio>
#include <algorithm>
using namespace std;
static const int maxm = 10000 + 50;
static const int maxx = 10000000 + 50;
typedef long long LL;
bool Notprime[maxx];
int inv[maxx],phi[maxx],fac[maxx],prime[maxx];
int T,n[maxm],m[maxm],p,cnt,tot;

void Read(int &);

inline void Linear_shaker(){
    int maxn = tot+1;
    fac[1]=1;inv[1]=1;phi[1]=1;
    for(register int i=2;i<maxn;i++){
        if(!Notprime[i])
            prime[++cnt]=i;
        for(register int j=1;j<=cnt && i*prime[j]<maxn;j++){
            Notprime[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
    for(register int i=2;i<=maxn;i++){
        fac[i] = ((LL)fac[i-1]*i)%p;
        if(i<p) inv[i] = (LL)(p-p/i)*inv[p%i]%p;
        if(!Notprime[i]) phi[i] = (LL)phi[i-1]*(i-1)%p*inv[i%p]%p;
        else phi[i] = phi[i-1];
    }
}
int main(){
    Read(T),Read(p);
    for(register int i=1;i<=T;i++) Read(n[i]),Read(m[i]),tot = max(tot,n[i]);
    Linear_shaker();
    for(register int i=1;i<=T;i++)
        printf("%lld\n",(LL)fac[n[i]]*phi[m[i]]%p);
    return 0;
}

void Read(int &in){
    static char ch;
    for(ch=getchar();ch>‘9‘||ch<‘0‘;ch=getchar()) ;
    for(in=0;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) in=in*10+ch-‘0‘;
}
时间: 2024-10-23 11:35:41

洛谷 P2155 BZOJ 2186 codevs 2301 [SDOI2008]沙拉公主的困惑的相关文章

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]沙拉公主的困惑

线性求逆元后好神的数论啊.... #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

【bzoj2186】: [Sdoi2008]沙拉公主的困惑 数论-欧拉函数

[bzoj2186]: [Sdoi2008]沙拉公主的困惑 考虑当 gcd(a,b)=1 则 gcd(nb+a,b)=1 所以[1,N!]与M!互质的个数就是 筛出[1,M]所有的素数p[i] 以及逆元 p[i]-1 处理一下前缀积inv[x]= 然后答案就是N!*inv[x] 1 /* http://www.cnblogs.com/karl07/ */ 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring&

【BZOJ2186】[Sdoi2008]沙拉公主的困惑 线性筛素数

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

[BZOJ 2186] [Sdoi2008] 沙拉公主的困惑 【欧拉函数】

题目链接:BZOJ - 2186 题目分析 题目要求出 [1, n!] 中有多少数与 m! 互质.(m <= n) 那么在 [1, m!] 中有 phi(m!) 个数与 m! 互质,如果一个数 x 与 m! 互质,即 gcd(m!, x) = 1, 那么 gcd(m!, m! + x) = 1, gcd(m!, m! * 2 + x) = 1, 即 x + k * m! 都与 m! 互质. 这样就很明确了,[1, n!] 中与 m! 互质的数有 phi(m!) * n! / m! 个. 怎么求