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

39 篇文章 0 订阅
10 篇文章 0 订阅

题目在这里呀!

Solution

又是一道数论题耶!本来感觉又要反演了,其实不用的。

多组数据,每次给定N,M的值,求(\sum_{i=1}^{N!} [gcd(i,M!)==1] )%R

可以想到,如果gcd(i,M!)=1,那么gcd(i+k*(M!),M!)=1.

所以询问就可以转化成\[(\sum_{i=1}^{M!}[gcd(i,M!)==1])(N!/M!)\]


即φ(M!)*(N!/M!).

前者展开,即M!*  (p-1)/p (p|M! && p is prime)

因为p为质数,所以p|M!即p|M。所以只要预处理出阶乘和(p-1)/p的乘积即可。

这样的话这道题就可以过啦~


再附上线性求逆元的证明吧。

inv[i]=(mod-mod/i)*inv[mod % i];

Proof

令x=mod/i,y=mod % i

则xi+y=0(%mod)

-xi=y(%mod)

同除以i*y得,-x*inv[y]=inv[i](%mod)

所以inv[i]=(mod-mod/i)*inv[mod % i]。

证毕!



#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 10000000+1000
using namespace std;
int T,mod,tot,vis[N],prime[N],fac[N],inv[N],mul[N];
long long ans;
int main()
{
	scanf("%d%d",&T,&mod);
	for(int i=2;i<=N;i++){
		if(!vis[i]) prime[++tot]=i;
		for(int j=1;j<=tot && i*prime[j]<=N;j++){
			vis[i*prime[j]]=1;
			if(i % prime[j]==0) break;
		}
	}
	fac[0]=1;
	for(int i=1;i<=N;i++) fac[i]=(long long)fac[i-1]*i % mod;
	inv[0]=inv[1]=1;
	for(int i=2;i<=N;i++) inv[i]=(long long)(mod-mod/i)*inv[mod % i] % mod;
	mul[1]=1;
	for(int i=2;i<=N;i++){
		mul[i]=mul[i-1];
		if(!vis[i]) mul[i]=(long long)mul[i]*(i-1) % mod * inv[i] % mod;
	}
	while(T--){
		int n,m;
		scanf("%d%d",&n,&m);
		ans=(long long)fac[n]*mul[m] % mod;
		printf("%lld\n",ans);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值