1. 程式人生 > >【洛谷P2155】[SDOI2008]沙拉公主的困惑

【洛谷P2155】[SDOI2008]沙拉公主的困惑

bsp 題目 ostream prim prime oid std 階乘 def

題目描述

大富翁國因為通貨膨脹,以及假鈔泛濫,政府決定推出一項新的政策:現有鈔票編號範圍為1到N的階乘,但是,政府只發行編號與M!互質的鈔票。房地產第一大戶沙拉公主決定預測一下大富翁國現在所有真鈔票的數量。現在,請你幫助沙拉公主解決這個問題,由於可能張數非常大,你只需計算出對R取模後的答案即可。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

分析(轉載)

原文地址

首先,我們來引出一個定理
如果$a$與$b$互質,那麽$b*k+a$也與$b$互質。證明和證明$gcd$的證明類似。
反過來,我們也可以用$gcd$證明,
因為$gcd(a,b)=1$,所以$gcd(a\%b,b)=1$
因為$a\%b=a-k*b$,故$gcd(a-k*b,b)=1$,及$a-k*b$與$b$互質。
根據這個特性,並且$n>=m$,所以可以將$n!$分成若幹段,每段為$m!$,每一段中與$m!$互質的個數都是相等的且等於1到$m!$中與$m!$互質的個數


我們可以得到式子

$ans={\frac{n!}{m!}*\phi(m!)}$

進一步拆開,我們可以得到 (假設$p$為$m!$的質因數,很容易可以知道,$p$就是所有小於$m$的素數,$r$為質因數個數)

$ans={\frac{n!}{m!}*m!*\frac{\prod \limits_{i=1}^{r}(p_i-1)}{\prod\limits_{i=1}^{r}p_i } \to ans=n!*\frac{\prod \limits_{i=1}^{r}(p_i-1)}{\prod\limits_{i=1}^{r}p_i } }$

因為$ans$ 要$\mod R$,所以我們也要算1到m的逆元,在累乘$\prod\limits_{i=1}^{r}p_i$ ,乘的是$p_i$ 的逆元。 有多組詢問,我們得先預處理一些數據,累乘的時候要$%R$ 我們令$k[i] = i!$ ,$inv[i]$為$i$的逆元,

$f1[i]= {\prod\limits_{a=1}^{i}(p_a-1)}$
$f2[i]={\prod\limits_{a=1}^{i}p_a}$
$ans=f1[m]*f2[m]*k[n]$
先預處理O()答案,對於詢問O(1)出解

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=10000000+1;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1; ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0; ch=getchar();}
    return x*f;
}
int T,p,n,m,tot;
int fac[maxn],inv[maxn],ans[maxn],prime[maxn];
bool isp[maxn];
void prework()
{
    fac[1]=1; inv[1]=1; ans[1]=1;
    for(int i=2;i<=maxn;i++)
    fac[i]=((ll)fac[i-1]*(i%p))%p;
    for(int i=2;i<=maxn;i++)
    inv[i]=(ll)(p-p/i)*inv[p%i]%p;
    for(int i=2;i<=maxn;i++)
    {
        if(!isp[i]) prime[++tot]=i;
        for(int j=1;j<=tot&&prime[j]*i<=maxn;j++)
        {
            isp[prime[j]*i]=1;
            if(i%prime[j]==0) break;
        }
    }
    for(int i=2;i<=maxn;i++)
    {
        if(!isp[i])
            ans[i]=(ll)ans[i-1]*(i-1)%p*inv[i%p]%p;
        else ans[i]=ans[i-1];
    }
}
int main()
{
    T=read();p=read();
    prework();
    while(T--)
    {
        n=read();m=read();
        printf("%d\n",(ll)fac[n]*ans[m]%p);
    }
    return 0;
}

【洛谷P2155】[SDOI2008]沙拉公主的困惑