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