Luogu P2155 [SDOI2008]沙拉公主的困惑___欧拉函数+gcd

9 篇文章 0 订阅
8 篇文章 0 订阅

题目大意:

T组数据, T &lt; = 10000 T&lt;=10000 T<=10000
每组给出 m , n , m &lt; = n m,n,m&lt;=n m,n,m<=n
[ 1 , n ! ] [1,n!] [1,n!]中与 m ! m! m!互质的数,结果对p取模 p &lt; = 1 0 9 + 10 p&lt;=10^9+10 p<=109+10
1 &lt; = n , m &lt; = 10000000 1 &lt; = n , m &lt; = 10000000 1<=n,m<=10000000

分析:

g c d ( a , b ) = 1 ( a x 1 + b y 1 = 1 ) gcd(a,b)=1(ax1+by1=1) gcd(a,b)=1(ax1+by1=1)
则有 g c d ( a + b , b ) = 1 [ a x 2 + b ( x 2 + y 2 ) = 1 ] gcd(a+b,b)=1[ax2+b(x2+y2)=1] gcd(a+b,b)=1[ax2+b(x2+y2)=1]
那么对于b而言,显然每b个数里面与b互质的数的数量相同
题目要求的是 g c d ( a , m ! ) = 1 ( a ∈ [ 1 , n ! ] ) gcd(a,m!)=1(a∈[1,n!]) gcd(a,m!)=1(a[1,n!])
那么因为 m ! ∣ n ! m!|n! m!n!
g c d ( a , m ! ) = 1 gcd(a,m!)=1 gcd(a,m!)=1则有 g c d ( a + m ! , m ! ) = 1 gcd(a+m!,m!)=1 gcd(a+m!,m!)=1
所以答案可以写成 φ ( m ! ) ∗ ( n ! / m ! ) φ(m!)*(n!/m!) φ(m!)(n!/m!)
也就是 ( m ! ∗ π i = 1 k ( p i − 1 ) / p i ) ∗ ( n ! / m ! ) (m!*π_{i=1}^{k}(p_i-1)/p_i)*(n!/m!) (m!πi=1k(pi1)/pi)(n!/m!)
约一下就是 π i = 1 k ( p i − 1 ) / p i ∗ n ! π_{i=1}^{k}(p_i-1)/p_i*n! πi=1k(pi1)/pin!
预处理一下然后O(1)回答即可

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring> 
#include <algorithm>

#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)
 
#define N 10000005

using namespace std;

typedef long long ll;

int pri[N], mul[N], inv[N], num[N], T, mulsum, mo, cnt;
bool vis[N];

void Pre_Work() {
	num[1] = 1;
	inv[1] = 1; rep(i, 2, N - 5) inv[i] = (ll)(mo - mo / i) * inv[mo % i] % mo;
    mul[0] = 1; rep(i, 1, N - 5) mul[i] = (ll)mul[i - 1] * i % mo;
	mulsum = 1;
    rep(i, 2, N - 5) {
    	if (!vis[i]) { pri[++cnt] = i; mulsum = (ll)mulsum * (i - 1) % mo * inv[i] % mo; }  
    	num[i] = mulsum;
		rep(j, 1, cnt) { 
    	    if ((ll)i * pri[j] > N - 5)  break;
    	    vis[i * pri[j]] = 1;
    		if (i % pri[j] == 0) break; 
    	}
    }
}

int main() { 
	scanf("%d %d", &T, &mo);
	Pre_Work();
	int L, R;
	rep(i, 1, T) {
		scanf("%d %d", &R, &L);
		int ans = (ll)mul[R] * num[L] % mo;
		ans = (ans % mo + mo) % mo;
		printf("%d\n", ans); 
	}
	return 0;  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值