Description
傳送門:http://www.lydsy.com/JudgeOnline/problem.php?id=2186
大富翁國因爲通貨膨脹,以及假鈔氾濫,政府決定推出一項新的政策:現有鈔票編號範圍爲1到N的階乘,但是,政府只發行編號與M!互質的鈔票。房地產第一大戶沙拉公主決定預測一下大富翁國現在所有真鈔票的數量。現在,請你幫助沙拉公主解決這個問題,由於可能張數非常大,你只需計算出對R取模後的答案即可。R是一個質數。
Input
第一行爲兩個整數T,R。R<=10^9+10,T<=10000,表示該組中測試數據數目,R爲模後面T行,每行一對整數N,M,見題目描述 m<=n
Output
共T行,對於每一對N,M,輸出1至N!中與M!素質的數的數量對R取模後的值
Sample Input
1 11
4 2
Sample Output
1
數據範圍:
對於100%的數據,1 < = N , M < = 10000000
題解
本題其實不算一個難題,題意顯然就是要求在N!內與M!互質的數的個數,我們先來看在M!內與M!互質的數,很顯然就是一個歐拉函數,可以線性的求出,那麼在N!內呢?顯然如果i與M!是互質的,那麼i+M!也與M!互質,i+2×M!也與M!互質,那麼在N!內與M!互質的個數即爲
又由於
所以又可以化爲
其中pi指的是M!的不同質因子,顯然這個式子中,
所以可以O(n)預處理,O(1)查詢;
下面我們來看看
代碼
/**************************************************************
Problem: 2186
User: zyg0121
Language: C++
Result: Accepted
Time:6408 ms
Memory:130196 kb
****************************************************************/
#include<cstdio>
#include<cmath>
#include<ctime>
#include<cstring>
#include<iostream>
#include<algorithm>
const int inf = 1000000000;
const int N = 10000000;
typedef long long ll ;
using namespace std;
int read() {
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9') {
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
int T,R,n,m,cnt;
int fac[10000005],ine[10000005],pri[500005],ans[10000005];
bool mark[10000005];
void exgcd(int a,int b,int &x,int &y) {
if(b==0) {
x=1;
y=0;
return;
}
exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
}
int getine(int t) {
int x,y;
exgcd(t,R,x,y);
return (x%R+R)%R;
}
void pre() {
fac[1]=1;
for(int i=2; i<=N; i++)fac[i]=(ll)fac[i-1]*i%R;
ine[1]=1;
for(int i=2; i<=N; i++) {
if(!mark[i])pri[++cnt]=i,ine[i]=getine(i);
for(int j=1; pri[j]*i<=N&&j<=cnt; j++) {
mark[pri[j]*i]=1;
if(i%pri[j]==0)break;
}
}
ans[1]=1;
for(int i=2; i<=N; i++) {
ans[i]=ans[i-1];
if(!mark[i])ans[i]=(ll)ans[i]*(i-1)%R*ine[i]%R;
}
}
int main() {
T=read();
R=read();
pre();
while(T--) {
n=read();
m=read();
printf("%d\n",(ll)fac[n]*ans[m]%R);
}
return 0;
}
下面有一份80分的在線代碼,最後幾個點RE,煩請大神幫幫蒟蒻吧!!!
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
const int size = 1000000+50;
typedef long long LL;
LL f[size],p[size],a[size];
int now = 1,top = 1,tot = 1;
int r,n,m;
int prime[500050];
bool v[size];
void isprime() {
LL ans=0;
for(int i=2; i<=size; i++) {
if(!v[i]) prime[++ans]=i;
for(int j=1; j<=ans&&i*prime[j]<=size; j++) {
v[i*prime[j]]=true;
if(i%prime[j]==0)
break;
}
}
return ;
}
void mod(int t) {
while(top<t)
f[++top]=f[top-1]*(top%r)%r;
}
LL inv (int t) {
if(t<=tot)
return p[t];
else
while(tot<t)
p[++tot]=(r-r/tot)*p[r%tot]%r;
return p[tot];
}
LL ans(int t) {
if(t<=now)
return a[t];
while(now<t) {
a[++now]=a[now-1];
if(!v[now])
a[now]=a[now]*(now-1)%r*inv(now%r)%r;
}
return a[t];
}
int main() {
int T;
scanf("%d%d",&T,&r) ;
isprime();
a[1]=1;p[0]=0;
p[1]=1;f[1]=1;
while(T--) {
scanf("%d%d",&n,&m);
if(n>top)
mod(n);
printf("%lld\n",f[n]*ans(m)%r);
}
return 0;
}