大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可。R是一个质数。
大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为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取模后的值
1356119 | 710395641 | 2186 | Accepted | 252764 kb | 11312 ms | C++/Edit | 1111 B | 2016-03-28 09:34:27 |
经大神点拨,我们观察式子:ans=N!(1-p1/1)(1-p2/1)...(1-pk/1),对于不同的询问,只有N!和k不同,既然能够预处理N!,何不预处理后面的乘积?进行O(M)的预处理,每次回答的复杂度降为O(1)。
总时间复杂度O( N + MloglogM + N + M + T) = O(N+MloglogM)
//bzoj2186 sdoi2008莎拉公主的困惑 #include <cstdio> #define ll long long #define maxn 10000000 #define maxk 1000000 using namespace std; ll p[maxk], R, inv[maxn+100], N, M, tot, fac[maxn+100], ans[maxn+100], T; bool no[maxn+100]; void getinv() { int i, m=(R<maxn?R:maxn); inv[1]=1; for(i=2;i<m;i++)inv[i]=(ll)(R-R/i)*inv[R%i]%R; } void shai() { int i, j; for(i=2;i<=maxn+1;i++) { if(!no[i])p[++tot]=i; for(j=1;i*p[j]<=maxn;j++) { no[i*p[j]]=true; if(i%p[j]==0)break; } } } void getfac() { int i; fac[1]=1; for(i=2;i<=maxn;i++)fac[i]=fac[i-1]*i%R; } void getans() { int i, j; ll t; ans[1]=1; for(i=1;i<=tot;i++) { t=(ll)ans[p[i]-1]*(p[i]-1)%R*inv[p[i]%R]%R; for(j=p[i];j<p[i+1];j++)ans[j]=t; } } int main() { int i; scanf("%d%d",&T,&R); shai(); getinv(); getfac(); getans(); while(T--) { scanf("%d%d",&N,&M); printf("%lld\n",fac[N]*ans[M]%R); } return 0; }