BZOJ-2186 (數論)

題目

2186: [Sdoi2008]沙拉公主的困惑
Time Limit: 10 Sec Memory Limit: 259 MB

Description

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

Input

第一行爲兩個整數T,R。R<=10^9+10,T<=10000,表示該組中測試數據數目,R爲模。
後面T行,每行一對整數N,M,見題目描述 m<=n
對於100%的數據,1 < = N , M < = 10000000

Output

共T行,對於每一對N,M,輸出1至N!中與M!素質的數的數量對R取模後的值

Sample Input

5 1000000007

35434 3244
10000000 1324
2316354 3243354
24223 242
1534234 123432

Sample Output

330733849
347925786
796298408
445433358
152561042

分析

程序

#include <cstdio>
#define N 10000002
typedef int ll;
ll i,j,T,k,Ha,n,m,ans,p[665000],v[N],g[N],h[N],num;
long long ret;
bool f[N];
//v:i的逆元    g:i的階乘     h:Pi((p[i]-1)/p[i],a[i]<=i)

ll ksm(ll x,ll y){
    for (ret=1; y; y>>=1,x=((long long)x*x)%Ha)
        if (y&1) ret=(long long)ret*x%Ha;
    return ret;
}

void get_p(){
    for (g[1]=h[1]=v[1]=1,i=2; i<N; i++){  
        g[i]=(long long)g[i-1]*i%Ha;
        v[i]=(long long)v[Ha%i]*(Ha-(Ha/i))%Ha;
        if (!f[i]){
            p[++num]=i;
            h[i]=(long long)h[i-1]*(i-1)%Ha*v[p[num]%Ha]%Ha;
        }else h[i]=h[i-1];
        for (j=1; j<=num && (long long)i*p[j]<N; j++){
            f[i*p[j]]=1;
            if(i%p[j]==0) break;
        }
    }
}

int main(){
    scanf("%d%d",&T,&Ha);
    get_p();
    while (T--){
        scanf("%d%d",&n,&m);
        ans=(long long)h[m]*g[n]%Ha;
        printf("%d\n",ans);
    }
}

提示

  • 還是取模的問題要細心考慮。
  • 逆元實際上只有 1~Ha-1 是需要算出來的,其它數的逆元都可以表示成 1/(i%Ha)
  • 第一次交居然 MLE 了……
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章