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 了……

猜你喜欢

转载自blog.csdn.net/jackypigpig/article/details/78372259