题目
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 < = 10000000Output
共T行,对于每一对N,M,输出1至N!中与M!素质的数的数量对R取模后的值
Sample Input
5 1000000007
35434 3244
10000000 1324
2316354 3243354
24223 242
1534234 123432Sample Output
330733849
347925786
796298408
445433358
152561042
分析
- 题目就是问 1~(n!) 有几个数与 m! 互质,答案对 R 取模。
- 我是真不会这题,看了这篇博文才懂的,放过来吧。
- (http://blog.csdn.net/PoPoQQQ/article/details/39957117)
程序
#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 了……