浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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

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

Solution

因为保证\(m<=n\)
所以有\(m!|n!\)
因为\(m!\)内与\(m!\)互质的数为\(\phi(m!)\)
所以\(ans = \phi(m!)*\frac{n!}{m!}\)(相当于把\(n!\)分成多段,每段\(m!\)

\[\large \begin{align*} ans &= \phi(m!)*\frac{n!}{m!}\\ &=\frac{n!}{m!}*m!*\frac{\prod{p[i]-1}}{\prod{p[i]}}\\ &=n!*\frac{\prod{(p[i]-1)}}{\prod{p[i]}} \end{align*}\\ \]

然后直接做就行了

#include <cstdio>
#include <iostream>
#include <bitset>

#define ll long long
#define inf 0x3f3f3f3f
#define il inline

int read()
{
    char x;
    while((x = getchar()) > '9' || x < '0') ;
    int u = x - '0';
    while((x = getchar()) <= '9' && x >= '0') u = (u << 3) + (u << 1) + x - '0';
    return u;
}
int buf[105];  
inline void write(int i) {  
    int p = 0;  
    if(i == 0) p++;  
    else while(i) {  
        buf[p++] = i % 10;  
        i /= 10;  
    }  
    for(int j = p-1; j >= 0; j--) putchar('0' + buf[j]);  
} 

using namespace std ;

#define N 10000010

int T, mod;
ll fac[N], inv[N];
ll ans[N];
bitset<N> pri;
// m <= n -> m!|n!
// 所以 n!中与m!互质的数的个数为 phi(m!)*(n!/m!) 

int main() {
	pri.set();
    for(int i = 2; i < N; ++i) {
    	if(pri[i])
    		for(int j = i + i; j < N; j += i) pri[j] = 0;
	}
    
    T = read(); mod = read();
    fac[0] = 1; 
    for(int i = 1; i < N; ++i) fac[i] = fac[i - 1] * i % mod;
    inv[0] = inv[1] = 1; 
    for(int i = 2; i < N; ++i) {
        if(i >= mod) break;
        inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    }
    ans[1] = 1;
    for(int i = 2; i < N; i ++) {
        if(pri[i]) {
            ans[i] = ans[i - 1] * (i - 1) % mod;
            ans[i] = ans[i] * inv[i % mod] % mod;
        } else ans[i] = ans[i - 1];
    }
	int n, m;
    while(T--) {
        n = read(); m = read();
        ll ANS = fac[n] * ans[m] % mod;
    	write(ANS), putchar('\n');
    }
    return 0;
}
posted @ 2019-01-01 22:35  henry_y  阅读(147)  评论(0编辑  收藏  举报