您的位置:首页 > 其它

BZOJ 2186: [Sdoi2008]沙拉公主的困惑 (逆元的应用)

2016-08-10 11:06 363 查看
传送门

Problem 2186. – [Sdoi2008]沙拉公主的困惑

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

Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 3058 Solved: 1040
[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

解题思路:

首先我们需要知道的一个知识点就是:对于两个正整数n 和 m,如果 n 是 m 的倍数,那么 [1,n]

中与 m 互素的数的个数为 nm∗phi(m)

那么现在在这个题中,让你求的是 [1,N!] 中与 M! (m≤n) 互素的个数,那么狠明显的是 N!

是 M! 的倍数,那么我们就可以运用刚才所说的知识点: 我们要求的结果就是 :

ans=N!M!∗Phi(M!)

其中 Phi(M!) 的展开式就是 M!∗(1−1p1)∗(1−1p2)∗..∗(1−1pk), p1p2...pk都是

≤M 的素数,所以ans=N!∗(1−1p1)∗(1−1p2)∗..∗(1−1pk) 因为有除法,所以我们就

需要处理逆元问题了,但是正常处理的话会超时,所以我们就引出来了一个新的公式:

Inv[i]=(Mod−Modi)∗Inv[Mod%i]%Mod

得到这个公式就行了,这个题目就可以完美解决了,首先我们预处理N! ,然后预处理逆元 Inv[i]

通过公式,其实最开始的时候不要忘记素数筛这样就行了。

My Code :

/**
2016 - 08 - 10 上午
Author: ITAK

Motto:

今日的我要超越昨日的我,明日的我要胜过今日的我,
以创作出更好的代码为目标,不断地超越自己。
**/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int MAXN = 1e7+50;
const double eps = 1e-7;
const double PI = acos(-1.0);
using namespace std;
bitset <MAXN> prime;
bool isprime()
{
prime.set();
for(int i=2; i<MAXN; i++)
if(prime[i])
for(int j=i+i; j<MAXN; j+=i)
prime[j] = false;
}
LL Inv[MAXN], fac[MAXN], ans[MAXN];
int main()
{
isprime();
LL R;
int N, M, T;
scanf("%d%lld",&T, &R);
Inv[1] = 1;
for(int i=2; i<MAXN; i++)
{
if(i >= R)
break;
Inv[i] = ( (R-R/i)*Inv[R%i] ) % R;
}
fac[0] = 1;
for(int i=1; i<MAXN; i++)
fac[i] = ( fac[i-1]*i ) % R;
ans[1] = 1;
for(int i=2; i<MAXN; i++)
{
if(prime[i])
{
ans[i] = ( ans[i-1]* (i-1) ) % R;
ans[i] = ( ans[i] * Inv[i%R] ) % R;
}
else
ans[i] = ans[i-1];
}
while(T--)
{
scanf("%d%d",&N,&M);
printf("%lld\n",ans[M]*fac
% R);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: