2186: [Sdoi2008]沙拉公主的困惑

来源:互联网 发布:我是淘宝骗保师 编辑:程序博客网 时间:2024/04/29 10:14

2186: [Sdoi2008]沙拉公主的困惑

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 3143  Solved: 1073
[Submit][Status][Discuss]

Description

  大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为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

HINT

Source

[Submit][Status][Discuss]

首先,由gcd(a,b) = gcd(a%b,b)得,gcd(a,b) = gcd(a+b,b)
所以,当我们每得知一组gcd(x,m!) == 1时,一定还有N!/M! - 1组(x一直+M!)
那么问题就变成求M!以内有多少个数与M!互质
这个值是phi(M!)
phi是积性函数,所以,根据phi的定义式,我们知道
phi[i!] = phi[(i-1)!]*i  (i不是素数)
phi[i!] = phi[(i-1)!]*(i-1) (i是素数)

综上所述,ans = phi(m!)*N!/M!
后面那个东西,开个线段树维护就好
#include<iostream>#include<cstdio>#include<queue>#include<vector>#include<bitset>#include<algorithm>#include<cstring>#include<map>#include<stack>#include<set>#include<cmath>#include<ext/pb_ds/priority_queue.hpp>using namespace std;const int maxn = 1E7 + 10;typedef long long LL;int T,mo,tot,tail,fac_phi[maxn],prime[maxn],c[maxn*4],N[10010],M[10010];bool not_prime[maxn];void Build(int o,int l,int r){if (l == r) {c[o] = l; return;}int mid = (l + r) >> 1;Build(2*o,l,mid); Build(2*o+1,mid+1,r);c[o] = 1LL*c[2*o]*c[2*o+1]%mo;} int Query(int o,int l,int r,int ql,int qr){if (ql <= l && r <= qr) return c[o];int mid = (l + r) >> 1,ret = 1;if (ql <= mid) ret = Query(2*o,l,mid,ql,qr);if (qr > mid) ret = 1LL*ret*Query(2*o+1,mid+1,r,ql,qr)%mo;return ret;}int main(){#ifdef DMCfreopen("DMC.txt","r",stdin);#endifcin >> T >> mo; fac_phi[0] = 1;not_prime[1] = 1;for (int i = 1; i <= T; i++) {scanf("%d%d",&N[i],&M[i]);tail = max(tail,N[i]);}for (int i = 2; i <= tail; i++) {if (!not_prime[i]) prime[++tot] = i; for (int j = 1; j <= tot; j++) {LL Nex = 1LL*i*prime[j];if (Nex > tail) break;not_prime[Nex] = 1;if (i % prime[j] == 0) break;}}Build(1,1,tail);for (LL i = 1; i <= tail; i++) if (not_prime[i]) fac_phi[i] = 1LL*fac_phi[i-1]*i%mo;else fac_phi[i] = 1LL*fac_phi[i-1]*(i-1)%mo;for (int i = 1; i <= T; i++) printf("%d\n",1LL*fac_phi[M[i]]*Query(1,1,tail,M[i]+1,N[i])%mo); return 0;}

0 0