大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可。R是一个质数。
标签:
传送门
Problem 2186. – [Sdoi2008]沙拉公主的困惑
大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可。R是一个质数。
第一行为两个整数T,R。R<=10^9+10,T<=10000,表示该组中测试数据数目,R为模后面T行,每行一对整数N,M,见题目描述 m<=n
共T行,对于每一对N,M,输出1至N!中与M!素质的数的数量对R取模后的值
解题思路:
首先我们需要知道的一个知识点就是:对于两个正整数
中与
那么现在在这个题中,让你求的是
是
需要处理逆元问题了,但是正常处理的话会超时,所以我们就引出来了一个新的公式:
得到这个公式就行了,这个题目就可以完美解决了,首先我们预处理
通过公式,其实最开始的时候不要忘记素数筛这样就行了。
/**
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[N] % R);
}
return 0;
}
BZOJ 2186: [Sdoi2008]沙拉公主的困惑 (逆元的应用)
标签:
原文地址:http://blog.csdn.net/qingshui23/article/details/52169527